1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22 * therefore common sense dictates that if they are part of a compound statement then they
23 * should be indented to the same level as everything else in that compound statement.
24 * Indenting curly braces at the same level as the "if" implies that curly braces are
25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27 * understand why variable y is not of type "char*" just proves the point that poor code
28 * layout leads people to unfortunate misunderstandings about how the C language really works.)
30 Change History (most recent first):
33 Revision 1.434 2009/06/27 00:55:27 cheshire
34 Added code for displaying the size of various structures like CacheRecord and CacheGroup
36 Revision 1.433 2009/06/25 23:36:57 cheshire
37 To facilitate testing, added command-line switch "-OfferSleepProxyService"
38 to re-enable the previously-supported mode of operation where we offer
39 sleep proxy service on desktop Macs that are set to never sleep.
41 Revision 1.432 2009/05/13 17:25:33 mkrochma
42 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
43 Sleep proxy client should only look for services being advertised via Multicast
45 Revision 1.431 2009/05/12 23:21:18 cheshire
46 <rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
47 Use mDNSCoreHaveAdvertisedServices routine to determine whether we should schedule a maintenance wake
49 Revision 1.430 2009/05/01 19:17:36 cheshire
50 <rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
52 Revision 1.429 2009/04/30 20:07:50 mcguire
53 <rdar://problem/6822674> Support multiple UDSs from launchd
55 Revision 1.428 2009/04/22 19:43:37 cheshire
56 To facilitate debugging, added -DebugLogging and -UnicastPacketLogging switches
57 as launch-time alternatives to sending SIGUSR1 and SIGUSR2 signals later
59 Revision 1.427 2009/04/22 01:19:57 jessic2
60 <rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
62 Revision 1.426 2009/04/20 19:25:26 cheshire
63 For readability, changed "nomulticastadvertisements" to "NoMulticastAdvertisements"
65 Revision 1.425 2009/04/20 19:17:19 cheshire
66 Added a comment explaining why we don't need our CatchABRT handler on 10.5 and later
68 Revision 1.424 2009/04/17 19:10:27 mcguire
69 <rdar://problem/6802833> May still ping-pong with kernel when a framework calls abort()
71 Revision 1.423 2009/04/16 16:03:08 mcguire
72 <rdar://problem/6792024> abort() causes high CPU usage instead of crash & restart
74 Revision 1.422 2009/04/11 01:43:28 jessic2
75 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
77 Revision 1.421 2009/04/11 00:20:06 jessic2
78 <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
80 Revision 1.420 2009/03/20 23:53:03 jessic2
81 <rdar://problem/6646228> SIGHUP should restart all in-progress queries
83 Revision 1.419 2009/03/20 21:30:04 cheshire
84 <rdar://problem/6705866> Crash passing invalid parameters to DNSServiceBrowserCreate()
85 Do not append a new question to the browser list until *after* we verify that mDNS_StartBrowse() succeeded
87 Revision 1.418 2009/03/17 21:32:15 cheshire
88 Improved "DHCPWakeTime: SCDynamicStoreCopyDHCPInfo failed" error message
90 Revision 1.417 2009/03/17 01:25:39 cheshire
91 <rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
92 In SIGINFO output, show three best Sleep Proxies
94 Revision 1.416 2009/02/21 01:47:36 cheshire
95 <rdar://problem/6600825> Race condition when sleep initiated and then immediately canceled
97 Revision 1.415 2009/02/21 01:45:33 cheshire
98 Move declaration of "mDNSs32 interval"
100 Revision 1.414 2009/02/14 00:05:32 cheshire
101 Left-justify interface names
103 Revision 1.413 2009/02/13 18:16:05 cheshire
104 Fixed some compile warnings
106 Revision 1.412 2009/02/13 06:34:41 cheshire
107 Converted LogOperation messages to LogInfo or LogSPS
109 Revision 1.411 2009/02/12 20:57:26 cheshire
110 Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
112 Revision 1.410 2009/02/11 02:32:18 cheshire
113 m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
115 Revision 1.409 2009/02/09 21:16:14 cheshire
116 Improved debugging messages
118 Revision 1.408 2009/02/07 06:08:44 cheshire
119 Commented out testing code
121 Revision 1.407 2009/02/07 02:57:31 cheshire
122 <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
124 Revision 1.406 2009/02/06 03:06:49 mcguire
125 <rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
127 Revision 1.405 2009/02/04 23:00:28 cheshire
128 Move logic for deciding when to next wake up into a subroutine called AllowSleepNow
130 Revision 1.404 2009/02/02 22:18:32 cheshire
131 If we wake up and find no wireless network, don't just give up and go back to sleep and never try again
133 Revision 1.403 2009/01/15 21:58:18 cheshire
134 Stop using ifa_name field of NetworkInterfaceInfoOSX structure, because it will be going away
136 Revision 1.402 2009/01/07 23:08:18 cheshire
137 Updated debugging messages and comments
139 Revision 1.401 2008/12/17 05:05:26 cheshire
140 Fixed alignment of NAT mapping syslog messages
142 Revision 1.400 2008/12/10 19:30:57 cheshire
143 Use symbolic name OSXVers_10_3_Panther in version check instead of literal integer "7"
145 Revision 1.399 2008/12/10 02:13:04 cheshire
146 Fix alignment of SIGINFO output for longer interface names like "bridge0"
148 Revision 1.398 2008/12/04 21:08:51 mcguire
149 <rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
151 Revision 1.397 2008/12/04 02:18:50 cheshire
152 Improved sleep/wake debugging messages
154 Revision 1.396 2008/11/26 23:37:44 cheshire
155 Use SCDynamicStoreCopyDHCPInfo to compute desired wakeup time for our next DHCP lease renewal
157 Revision 1.395 2008/11/14 21:56:31 cheshire
158 Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c
160 Revision 1.394 2008/11/14 02:20:03 cheshire
161 Include m->NextScheduledSPS in task scheduling calculations
163 Revision 1.393 2008/11/14 01:22:38 cheshire
164 Include SPS-registered records when computing the next required wakeup time
166 Revision 1.392 2008/11/11 01:55:16 cheshire
167 Improved comments; minium requested sleep is 60 seconds
169 Revision 1.391 2008/11/04 02:29:55 cheshire
170 Clear interface list before sleeping
172 Revision 1.390 2008/11/02 21:22:05 cheshire
173 Changed mallocL size parameter back to "unsigned int"
175 Revision 1.389 2008/11/02 21:14:58 cheshire
176 Fixes to make mallocL/freeL debugging checks work on 64-bit
178 Revision 1.388 2008/10/31 23:05:30 cheshire
179 Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c
181 Revision 1.387 2008/10/30 01:08:18 cheshire
182 After waking for network maintenance operations go back to sleep again
184 Revision 1.386 2008/10/29 22:03:39 cheshire
185 Compute correct required wakeup time for NAT traversals and uDNS-registered records
187 Revision 1.385 2008/10/28 20:40:13 cheshire
188 Now that the BPF code in mDNSMacOSX.c makes its own CFSocketCreateWithNative directly, the
189 udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop routines can go back to using kqueue
191 Revision 1.384 2008/10/27 22:22:59 cheshire
192 Extra sanity checking in udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop
194 Revision 1.383 2008/10/27 07:24:53 cheshire
195 Need a "usleep(1000)" (workaround for <rdar://problem/3585273>) to avoid crashes
197 Revision 1.382 2008/10/24 01:51:48 cheshire
198 Before going to sleep, request a future wakeup to renew NAT-PMP mappings, SPS registrations, etc.
200 Revision 1.381 2008/10/23 22:25:58 cheshire
201 Renamed field "id" to more descriptive "updateid"
203 Revision 1.380 2008/10/23 02:25:08 cheshire
204 Added locking in InternetSharingChanged()
206 Revision 1.379 2008/10/22 23:23:59 cheshire
207 Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
209 Revision 1.378 2008/10/22 19:55:35 cheshire
210 Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
212 Revision 1.377 2008/10/22 17:17:22 cheshire
213 Need to open and close BPF fds when turning Sleep Proxy Server on and off
215 Revision 1.376 2008/10/22 01:42:39 cheshire
216 Before allowing sleep, delay until NetWakeResolve queries have completed
218 Revision 1.375 2008/10/20 22:31:31 cheshire
219 Instead of requesting a single BPF descriptor via mDNSRequestBPF(), call mDNSMacOSXNetworkChanged()
220 to signal that UDS is now available to handle BPF requests, and let it work out what it needs
222 Revision 1.374 2008/10/16 22:40:48 cheshire
223 Removed "usleep(100000);" from CFSCallBack()
225 Revision 1.373 2008/10/16 20:49:30 cheshire
226 When kevent/kqueue fails, fall back to using old CFSocket RunLoopSource instead
228 Revision 1.372 2008/10/15 00:03:21 cheshire
229 When finally going to sleep, update m->SleepState from SleepState_Transferring to SleepState_Sleeping
231 Revision 1.371 2008/10/14 19:09:53 cheshire
232 When going to sleep, delay sleep until we've got our acknowledgment from the SPS
234 Revision 1.370 2008/10/09 22:32:27 cheshire
235 Include MAC address in interface listing in SIGINFO output
237 Revision 1.369 2008/10/09 19:32:39 cheshire
238 Updated SIGINFO output to indicate whether we've found a sleep proxy server on a given interface
239 Hollow sun with rays "☼" indicates we're still looking; solid sun with rays "☀" indicates we found one
241 Revision 1.368 2008/10/03 21:23:17 mkrochma
242 Fix crash by not passing NULL to CFGetTypeID
244 Revision 1.367 2008/10/03 18:25:17 cheshire
245 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
247 Revision 1.366 2008/10/03 00:34:55 cheshire
248 <rdar://problem/6134215> Mac with Internet Sharing should also offer Sleep Proxy service
249 Start and stop Sleep Proxy service when user starts and stops Internet Sharing
251 Revision 1.365 2008/10/02 22:23:13 cheshire
252 Additional debugging message giving explanation if shutdown is delayed
254 Revision 1.364 2008/10/01 21:23:40 cheshire
255 In SIGINFO interface listing, indicate whether NetWake is set
257 Revision 1.363 2008/09/27 01:29:15 cheshire
258 Call mDNSRequestBPF() to request the helper to send us the BPF fd
260 Revision 1.362 2008/09/26 19:47:42 cheshire
261 Fixed locking error: lock is supposed to be held when calling mDNS_PurgeCacheResourceRecord
263 Revision 1.361 2008/09/15 23:52:30 cheshire
264 <rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
265 Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
267 Revision 1.360 2008/03/13 20:55:16 mcguire
268 <rdar://problem/5769316> fix deprecated warnings/errors
269 Additional cleanup: use a conditional macro instead of lots of #if
271 Revision 1.359 2008/03/12 23:02:58 mcguire
272 <rdar://problem/5769316> fix deprecated warnings/errors
274 Revision 1.358 2008/03/06 21:26:11 cheshire
275 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
277 Revision 1.357 2008/02/13 17:40:43 cheshire
278 <rdar://problem/5740501> Investigate mysterious SIGABRTs in mDNSResponder
280 Revision 1.356 2007/12/18 00:28:56 cheshire
281 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
282 Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
284 Revision 1.355 2007/12/17 22:29:22 cheshire
285 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
286 Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
288 Revision 1.354 2007/12/15 01:12:28 cheshire
289 <rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
291 Revision 1.353 2007/12/14 19:14:02 cheshire
292 Added (commented out) code for testing sleep/wake
294 Revision 1.352 2007/12/14 00:58:29 cheshire
295 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
296 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
297 until TLS/TCP deregistrations have completed (up to five seconds maximum)
299 Revision 1.351 2007/12/12 21:34:18 cheshire
300 Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
301 it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
302 confirmed that the bug is definitely fixed we'll remove the workaround altogether.
304 Revision 1.350 2007/12/07 00:45:58 cheshire
305 <rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
307 Revision 1.349 2007/12/04 22:00:54 cheshire
308 Fixed mistake in comment
310 Revision 1.348 2007/12/01 00:27:43 cheshire
311 Fixed compile warning: declaration of 'r' shadows a previous local
313 Revision 1.347 2007/11/02 22:00:13 cheshire
314 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
315 Need to hold the lock while calling SetDomainSecrets
317 Revision 1.346 2007/11/02 20:18:13 cheshire
318 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
320 Revision 1.345 2007/10/17 18:41:21 cheshire
321 For debugging, make SIGUSR1 simulate a KeychainChanged event as well as a NetworkChanged
323 Revision 1.344 2007/09/29 01:06:17 mcguire
324 <rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
326 Revision 1.343 2007/09/24 05:02:41 cheshire
327 Debugging: In SIGINFO output, indicate explicitly when a given section is empty
329 Revision 1.342 2007/09/18 19:09:02 cheshire
330 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
332 Revision 1.341 2007/09/12 01:22:13 cheshire
333 Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
335 Revision 1.340 2007/09/07 22:44:03 mcguire
336 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
338 Revision 1.339 2007/09/06 19:08:29 cheshire
339 LogClientOperations check needs to be "#if LogClientOperations || MDNS_DEBUGMSGS"
341 Revision 1.338 2007/09/05 23:34:27 mcguire
342 Revert logging change
344 Revision 1.337 2007/09/05 20:45:50 cheshire
345 Added list of KQSocketEventSources in SIGINFO output
347 Revision 1.336 2007/08/31 17:15:37 cheshire
348 Reordered startup log messages so that "mDNSResponder ... starting" is the first message
350 Revision 1.335 2007/08/31 02:00:16 cheshire
351 Added comment explaining use of zero-width non-breaking space character to tag literal strings
353 Revision 1.334 2007/08/24 23:40:24 cheshire
354 Added comment about FreeServiceInstance
356 Revision 1.333 2007/08/23 21:02:35 cheshire
357 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
359 Revision 1.332 2007/08/22 23:54:54 mcguire
360 <rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
362 Revision 1.331 2007/08/18 01:02:03 mcguire
363 <rdar://problem/5415593> No Bonjour services are getting registered at boot
365 Revision 1.330 2007/08/10 22:25:57 mkrochma
366 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
368 Revision 1.329 2007/08/08 22:34:58 mcguire
369 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
371 Revision 1.328 2007/07/27 22:43:37 cheshire
372 Improved mallocL/freeL "suspiciously large" debugging messages
374 Revision 1.327 2007/07/27 19:30:41 cheshire
375 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
376 to properly reflect tri-state nature of the possible responses
378 Revision 1.326 2007/07/24 17:23:33 cheshire
379 <rdar://problem/5357133> Add list validation checks for debugging
381 Revision 1.325 2007/07/11 23:43:43 cheshire
382 Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
384 Revision 1.324 2007/07/11 22:44:40 cheshire
385 <rdar://problem/5328801> SIGHUP should purge the cache
387 Revision 1.323 2007/07/11 03:01:50 cheshire
388 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
390 Revision 1.322 2007/07/06 18:58:16 cheshire
391 Check m->NextScheduledNATOp in ShowTaskSchedulingError()
393 Revision 1.321 2007/07/02 21:54:20 cheshire
394 Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
396 Revision 1.320 2007/06/28 21:16:27 cheshire
397 Rename "m->nextevent" as more informative "m->NextuDNSEvent"
399 Revision 1.319 2007/06/22 20:47:08 cheshire
400 <rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
401 Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
403 Revision 1.318 2007/06/20 01:45:40 cheshire
404 When showing dormant interfaces, display last-seen IP address for that dormant interface
406 Revision 1.317 2007/06/20 01:10:12 cheshire
407 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
409 Revision 1.316 2007/06/19 19:27:11 cheshire
410 <rdar://problem/5141540> Sandbox mDNSResponder
411 Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
413 Revision 1.315 2007/06/15 21:54:51 cheshire
414 <rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
416 Revision 1.314 2007/06/15 19:23:17 cheshire
417 <rdar://problem/5254053> mDNSResponder renames my host without asking
418 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
420 Revision 1.313 2007/05/25 16:02:05 cheshire
421 When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
423 Revision 1.312 2007/05/22 19:07:21 cheshire
424 Add comment explaining RR_CACHE_SIZE calculation
426 Revision 1.311 2007/05/15 21:47:21 cheshire
427 Get rid of "#pragma unused(m)"
429 Revision 1.310 2007/05/08 00:56:17 cheshire
430 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
432 Revision 1.309 2007/04/30 21:33:38 cheshire
433 Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
434 is iterating through the m->ServiceRegistrations list
436 Revision 1.308 2007/04/28 01:31:59 cheshire
437 Improve debugging support for catching memory corruption problems
439 Revision 1.307 2007/04/24 18:32:00 cheshire
440 Grab a copy of KQtask string pointer in case KQcallback deletes the task
442 Revision 1.306 2007/04/22 19:11:51 cheshire
443 Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
444 if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
445 from the project and just using simple vanilla C linked-list manipulation instead.
447 Revision 1.305 2007/04/22 06:02:03 cheshire
448 <rdar://problem/4615977> Query should immediately return failure when no server
450 Revision 1.304 2007/04/21 21:47:47 cheshire
451 <rdar://problem/4376383> Daemon: Add watchdog timer
453 Revision 1.303 2007/04/18 00:50:47 cheshire
454 <rdar://problem/5141540> Sandbox mDNSResponder
456 Revision 1.302 2007/04/07 01:01:48 cheshire
457 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
459 Revision 1.301 2007/04/05 19:13:48 cheshire
460 Use better name in SCPreferencesCreate
462 Revision 1.300 2007/04/04 21:22:18 cheshire
463 Suppress "Local Hostname changed" syslog message when name has not actually changed
465 Revision 1.299 2007/04/03 19:19:33 cheshire
466 Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
468 Revision 1.298 2007/03/30 21:51:45 cheshire
471 Revision 1.297 2007/03/27 22:47:19 cheshire
472 On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
474 Revision 1.296 2007/03/24 01:23:29 cheshire
475 Call validator for uDNS data structures
477 Revision 1.295 2007/03/20 23:32:49 cheshire
478 Minor textual tidying
480 Revision 1.294 2007/03/07 02:50:50 cheshire
481 <rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
483 Revision 1.293 2007/03/06 22:59:01 cheshire
484 <rdar://problem/4157921> Security: Null dereference possible in daemon.c
486 Revision 1.292 2007/02/28 21:55:10 cheshire
487 <rdar://problem/3862944> UI: Name conflict notifications should be localized
488 Additional fix: We were not getting our NotificationCallBackDismissed messages
489 because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
490 (We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
492 Revision 1.291 2007/02/28 03:51:24 cheshire
493 <rdar://problem/3862944> UI: Name conflict notifications should be localized
494 Moved curly quotes out of the literal text and into the localized text, so they
495 can be replaced with alternate characters as appropriate for other languages.
497 Revision 1.290 2007/02/14 01:58:19 cheshire
498 <rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
500 Revision 1.289 2007/02/07 19:32:00 cheshire
501 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
503 Revision 1.288 2007/02/07 01:01:24 cheshire
504 <rdar://problem/3956518> Need to go native with launchd
505 Additional refinements -- was unnecessarily calling launch_data_free()
507 Revision 1.287 2007/02/06 19:06:48 cheshire
508 <rdar://problem/3956518> Need to go native with launchd
510 Revision 1.286 2007/01/06 01:00:33 cheshire
511 Improved SIGINFO output
513 Revision 1.285 2007/01/05 08:30:47 cheshire
514 Trim excessive "$Log" checkin history from before 2006
515 (checkin history still available via "cvs log ..." of course)
517 Revision 1.284 2007/01/05 05:44:35 cheshire
518 Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
519 so that mDNSPosix embedded clients will compile again
521 Revision 1.283 2007/01/04 23:11:14 cheshire
522 <rdar://problem/4720673> uDNS: Need to start caching unicast records
523 When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
525 Revision 1.282 2006/12/21 00:09:45 cheshire
526 Use mDNSPlatformMemZero instead of bzero
528 Revision 1.281 2006/11/18 05:01:32 cheshire
529 Preliminary support for unifying the uDNS and mDNS code,
530 including caching of uDNS answers
532 Revision 1.280 2006/11/10 00:54:16 cheshire
533 <rdar://problem/4816598> Changing case of Computer Name doesn't work
535 Revision 1.279 2006/11/02 17:44:01 cheshire
536 No longer have a separate uDNS ActiveQueries list
538 Revision 1.278 2006/10/05 04:04:24 herscher
539 Remove embedded uDNS_info struct from DNSQuestion_struct
541 Revision 1.277 2006/09/21 21:01:24 cheshire
542 Change 'autorename' to more accurate name 'renameonmemfree'
544 Revision 1.276 2006/09/17 19:12:02 cheshire
545 Further changes for removal of uDNS_info substructure from mDNS_struct
547 Revision 1.275 2006/09/15 21:20:16 cheshire
548 Remove uDNS_info substructure from mDNS_struct
550 Revision 1.274 2006/08/14 23:24:39 cheshire
551 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
553 Revision 1.273 2006/07/30 05:43:19 cheshire
554 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
555 Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
557 Revision 1.272 2006/07/27 03:24:35 cheshire
558 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
559 Further refinement: Declare KQueueEntry parameter "const"
561 Revision 1.271 2006/07/27 02:59:26 cheshire
562 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
563 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
564 after releasing BigMutex, in case actions it took have resulted in new work for the
565 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
566 add new active interfaces to its list, and consequently schedule queries to be sent).
568 Revision 1.270 2006/07/25 17:16:36 mkrochma
569 Quick fix to solve kqueue related crashes and hangs
571 Revision 1.269 2006/07/22 06:11:37 cheshire
572 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
574 Revision 1.268 2006/07/15 02:01:32 cheshire
575 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
576 Fix broken "empty string" browsing
578 Revision 1.267 2006/07/07 01:09:10 cheshire
579 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
580 Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
582 Revision 1.266 2006/07/05 23:34:53 cheshire
583 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
585 Revision 1.265 2006/06/29 07:32:08 cheshire
586 Added missing LogOperation logging for DNSServiceBrowse results
588 Revision 1.264 2006/06/29 05:33:30 cheshire
589 <rdar://problem/4607043> mDNSResponder conditional compilation options
591 Revision 1.263 2006/06/08 23:23:48 cheshire
592 Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
594 Revision 1.262 2006/03/18 21:49:11 cheshire
595 Added comment in ShowTaskSchedulingError(mDNS *const m)
597 Revision 1.261 2006/01/06 01:22:28 cheshire
598 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
602 #include <mach/mach.h>
603 #include <mach/mach_error.h>
604 #include <servers/bootstrap.h>
605 #include <sys/types.h>
611 #include <sys/event.h>
614 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
615 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
617 #if TARGET_OS_EMBEDDED
618 #include <bootstrap_priv.h>
620 #define bootstrap_register(A,B,C) bootstrap_register2((A),(B),(C),0)
623 #include "DNSServiceDiscoveryRequestServer.h"
624 #include "DNSServiceDiscoveryReply.h"
627 #include "DNSCommon.h"
628 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
630 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
632 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
634 #include "safe_vproc.h"
636 //*************************************************************************************************************
637 #if COMPILER_LIKES_PRAGMA_MARK
638 #pragma mark - Globals
641 static mDNS_PlatformSupport PlatformStorage
;
643 // Start off with a default cache of 16K (99 records)
644 // Each time we grow the cache we add another 99 records
645 // 99 * 164 = 16236 bytes.
646 // This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
647 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
648 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
650 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
651 static mach_port_t m_port
= MACH_PORT_NULL
;
652 static mach_port_t client_death_port
= MACH_PORT_NULL
;
653 static mach_port_t signal_port
= MACH_PORT_NULL
;
654 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
656 static dnssd_sock_t
*launchd_fds
= mDNSNULL
;
657 static mDNSu32 launchd_fds_count
= 0;
659 // mDNS Mach Message Timeout, in milliseconds.
660 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
661 // fails to service its mach message queue, but long enough to give a well-written
662 // client a chance to service its mach message queue without getting cut off.
663 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
664 // even extra-slow clients a fair chance before we cut them off.
665 #define MDNS_MM_TIMEOUT 250
667 static int restarting_via_mach_init
= 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism
668 static int started_via_launchdaemon
= 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd
669 static mDNSBool advertise
= mDNS_Init_AdvertiseLocalAddresses
; // By default, advertise addresses (& other records) via multicast
671 extern mDNSBool StrictUnicastOrdering
;
673 //*************************************************************************************************************
674 #if COMPILER_LIKES_PRAGMA_MARK
676 #pragma mark - Active client list structures
679 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
680 struct DNSServiceDomainEnumeration_struct
682 DNSServiceDomainEnumeration
*next
;
683 mach_port_t ClientMachPort
;
684 DNSQuestion dom
; // Question asking for domains
685 DNSQuestion def
; // Question asking for default domain
688 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
689 struct DNSServiceBrowserResult_struct
691 DNSServiceBrowserResult
*next
;
696 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
698 typedef struct DNSServiceBrowserQuestion
700 struct DNSServiceBrowserQuestion
*next
;
703 } DNSServiceBrowserQuestion
;
705 struct DNSServiceBrowser_struct
707 DNSServiceBrowser
*next
;
708 mach_port_t ClientMachPort
;
709 DNSServiceBrowserQuestion
*qlist
;
710 DNSServiceBrowserResult
*results
;
712 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
713 domainname type
; // registration type
716 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
717 struct DNSServiceResolver_struct
719 DNSServiceResolver
*next
;
720 mach_port_t ClientMachPort
;
726 // A single registered service: ServiceRecordSet + bookkeeping
727 // Note that we duplicate some fields from parent DNSServiceRegistration object
728 // to facilitate cleanup, when instances and parent may be deallocated at different times.
729 typedef struct ServiceInstance
731 struct ServiceInstance
*next
;
732 mach_port_t ClientMachPort
;
733 mDNSBool autoname
; // Set if this name is tied to the Computer Name
734 mDNSBool renameonmemfree
; // Set if we just got a name conflict and now need to automatically pick a new name
737 ServiceRecordSet srs
;
738 // Don't add any fields after ServiceRecordSet.
739 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
742 // A client-created service. May reference several ServiceInstance objects if default
743 // settings cause registration in multiple domains.
744 typedef struct DNSServiceRegistration
746 struct DNSServiceRegistration
*next
;
747 mach_port_t ClientMachPort
;
748 mDNSBool DefaultDomain
;
752 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
753 domainlabel name
; // used only if autoname is false
756 unsigned char txtinfo
[1024];
759 ServiceInstance
*regs
;
760 } DNSServiceRegistration
;
762 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
763 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
764 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
765 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
767 // We keep a list of client-supplied event sources in KQSocketEventSource records
768 typedef struct KQSocketEventSource
770 struct KQSocketEventSource
*next
;
773 } KQSocketEventSource
;
775 static KQSocketEventSource
*gEventSources
;
777 //*************************************************************************************************************
778 #if COMPILER_LIKES_PRAGMA_MARK
780 #pragma mark - General Utility Functions
783 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
785 char _malloc_options
[] = "AXZ";
787 mDNSexport
void LogMemCorruption(const char *format
, ...)
791 va_start(ptr
,format
);
792 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
794 LogMsg("!!!! %s !!!!", buffer
);
795 NotifyOfElusiveBug("Memory Corruption", buffer
);
797 *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
801 mDNSlocal
void validatelists(mDNS
*const m
)
804 KQSocketEventSource
*k
;
805 for (k
= gEventSources
; k
; k
=k
->next
)
806 if (k
->next
== (KQSocketEventSource
*)~0 || k
->fd
< 0)
807 LogMemCorruption("gEventSources: %p is garbage (%d)", k
, k
->fd
);
809 // Check Mach client lists
810 DNSServiceDomainEnumeration
*e
;
811 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
812 if (e
->next
== (DNSServiceDomainEnumeration
*)~0 || e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
813 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e
, e
->ClientMachPort
);
815 DNSServiceBrowser
*b
;
816 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
817 if (b
->next
== (DNSServiceBrowser
*)~0 || b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
818 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b
, b
->ClientMachPort
);
820 DNSServiceResolver
*l
;
821 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
822 if (l
->next
== (DNSServiceResolver
*)~0 || l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
823 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l
, l
->ClientMachPort
);
825 DNSServiceRegistration
*r
;
826 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
827 if (r
->next
== (DNSServiceRegistration
*)~0 || r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
828 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r
, r
->ClientMachPort
);
830 // Check Unix Domain Socket client lists (uds_daemon.c)
833 // Check core mDNS lists
835 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
837 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
838 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
839 if (rr
->resrec
.name
!= &rr
->namestorage
)
840 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
841 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
844 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
845 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
846 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
848 rr
= m
->NewLocalRecords
;
850 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
851 LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
853 rr
= m
->CurrentRecord
;
855 if (rr
->next
== (AuthRecord
*)~0 || rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
856 LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
859 for (q
= m
->Questions
; q
; q
=q
->next
)
860 if (q
->next
== (DNSQuestion
*)~0 || q
->ThisQInterval
== (mDNSs32
)~0)
861 LogMemCorruption("Questions list: %p is garbage (%lX %p)", q
, q
->ThisQInterval
, q
->next
);
866 FORALL_CACHERECORDS(slot
, cg
, cr
)
868 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
869 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot
, cr
, cr
->resrec
.RecordType
);
870 if (cr
->CRActiveQuestion
)
872 for (q
= m
->Questions
; q
; q
=q
->next
) if (q
== cr
->CRActiveQuestion
) break;
873 if (!q
) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot
, cr
->CRActiveQuestion
, CRDisplayString(m
, cr
));
877 // Check core uDNS lists
878 udns_validatelists(m
);
880 // Check platform-layer lists
881 NetworkInterfaceInfoOSX
*i
;
882 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
883 if (i
->next
== (NetworkInterfaceInfoOSX
*)~0 || !i
->m
|| i
->m
== (mDNS
*)~0)
884 LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i
, i
->ifinfo
.ifname
);
887 for (t
= m
->TunnelClients
; t
; t
=t
->next
)
888 if (t
->next
== (ClientTunnel
*)~0 || t
->dstname
.c
[0] > 63)
889 LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t
, t
->dstname
.c
[0]);
892 mDNSexport
void *mallocL(char *msg
, unsigned int size
)
894 // Allocate space for two words of sanity checking data before the requested block
895 mDNSu32
*mem
= malloc(sizeof(mDNSu32
) * 2 + size
);
897 { LogMsg("malloc( %s : %d ) failed", msg
, size
); return(NULL
); }
900 if (size
> 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg
, size
, &mem
[2]);
901 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
904 //mDNSPlatformMemZero(&mem[2], size);
905 memset(&mem
[2], 0xFF, size
);
906 validatelists(&mDNSStorage
);
911 mDNSexport
void freeL(char *msg
, void *x
)
914 LogMsg("free( %s @ NULL )!", msg
);
917 mDNSu32
*mem
= ((mDNSu32
*)x
) - 2;
918 if (mem
[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
919 if (mem
[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg
, mem
[1], &mem
[2]);
920 else if (MACOSX_MDNS_MALLOC_DEBUGGING
>= 2) LogMsg("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
921 //mDNSPlatformMemZero(mem, sizeof(mDNSu32) * 2 + mem[1]);
922 memset(mem
, 0xFF, sizeof(mDNSu32
) * 2 + mem
[1]);
923 validatelists(&mDNSStorage
);
930 //*************************************************************************************************************
931 #if COMPILER_LIKES_PRAGMA_MARK
933 #pragma mark - Mach client request handlers
936 //*************************************************************************************************************
937 // Client Death Detection
939 // This gets called after ALL constituent records of the Service Record Set have been deregistered
940 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
942 ServiceRecordSet
*s
= &x
->srs
;
943 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
947 e
->r
.RecordContext
= e
;
950 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
953 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
954 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
956 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
957 freeL("ServiceInstance", x
);
960 // AbortClient finds whatever client is identified by the given Mach port,
961 // stops whatever operation that client was doing, and frees its memory.
962 // In the case of a service registration, the actual freeing may be deferred
963 // until we get the mStatus_MemFree message, if necessary
964 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
966 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
967 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
968 DNSServiceResolver
**l
= &DNSServiceResolverList
;
969 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
971 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
974 DNSServiceDomainEnumeration
*x
= *e
;
977 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
978 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
979 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
980 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
981 freeL("DNSServiceDomainEnumeration", x
);
985 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
988 DNSServiceBrowser
*x
= *b
;
989 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
994 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
995 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
996 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
999 freeL("DNSServiceBrowserQuestion", freePtr
);
1003 DNSServiceBrowserResult
*t
= x
->results
;
1004 x
->results
= x
->results
->next
;
1005 freeL("DNSServiceBrowserResult", t
);
1007 freeL("DNSServiceBrowser", x
);
1011 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
1014 DNSServiceResolver
*x
= *l
;
1017 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
1018 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
1019 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
1020 freeL("DNSServiceResolver", x
);
1024 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
1027 ServiceInstance
*si
= NULL
;
1028 DNSServiceRegistration
*x
= *r
;
1034 ServiceInstance
*instance
= si
;
1036 instance
->renameonmemfree
= mDNSfalse
;
1037 if (m
&& m
!= x
) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
), m
, x
);
1038 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
1040 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
1041 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
1042 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
1043 // the list, so we should go ahead and free the memory right now
1044 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
1047 freeL("DNSServiceRegistration", x
);
1051 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
1054 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
1056 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
1058 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1059 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1060 DNSServiceResolver
*l
= DNSServiceResolverList
;
1061 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1062 DNSServiceBrowserQuestion
*qptr
;
1064 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1065 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1066 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1067 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1069 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
1072 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1073 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
1075 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
1078 ServiceInstance
*si
;
1079 for (si
= r
->regs
; si
; si
= si
->next
)
1080 LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
1082 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
1087 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
1089 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1090 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1091 DNSServiceResolver
*l
= DNSServiceResolverList
;
1092 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1093 DNSServiceBrowserQuestion
*qptr
;
1095 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1096 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1097 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1098 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1099 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
1102 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1103 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
1105 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
1106 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
1107 return(e
|| b
|| l
|| r
);
1110 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
1112 KQueueLock(&mDNSStorage
);
1113 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
1114 (void)unusedport
; // Unused
1115 (void)size
; // Unused
1116 (void)info
; // Unused
1117 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1119 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
1120 AbortClient(deathMessage
->not_port
, NULL
);
1122 /* Deallocate the send right that came in the dead name notification */
1123 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
1125 KQueueUnlock(&mDNSStorage
, "Mach AbortClient");
1128 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
1131 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
1132 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
1133 // If the port already died while we were thinking about it, then abort the operation right away
1134 if (r
!= KERN_SUCCESS
)
1135 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1138 //*************************************************************************************************************
1139 // Domain Enumeration
1141 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
1143 kern_return_t status
;
1144 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1145 DNSServiceDomainEnumerationReplyResultType rt
;
1146 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1149 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1150 if (answer
->rrtype
!= kDNSType_PTR
) return;
1151 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1155 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1156 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1160 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1164 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1165 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1166 !AddRecord
? "RemoveDomain" :
1167 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1169 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1170 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1171 if (status
== MACH_SEND_TIMED_OUT
)
1172 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1175 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1178 // Check client parameter
1179 (void)unusedserver
; // Unused
1180 mStatus err
= mStatus_NoError
;
1181 const char *errormsg
= "Unknown";
1182 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1183 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1185 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1186 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1188 // Allocate memory, and handle failure
1189 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1190 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1192 // Set up object, and link into list
1193 x
->ClientMachPort
= client
;
1194 x
->next
= DNSServiceDomainEnumerationList
;
1195 DNSServiceDomainEnumerationList
= x
;
1197 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1200 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1201 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1202 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1204 // Succeeded: Wrap up and return
1205 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1206 EnableDeathNotificationForClient(client
, x
);
1207 return(mStatus_NoError
);
1210 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%d)", client
, regDom
, errormsg
, err
);
1214 //*************************************************************************************************************
1215 // Browse for services
1217 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
1221 if (answer
->rrtype
!= kDNSType_PTR
)
1222 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1225 domainname type
, domain
;
1226 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1228 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1229 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1233 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1234 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1236 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1237 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1239 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1240 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1243 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1244 DNSServiceBrowserResult
**p
= &browser
->results
;
1245 while (*p
) p
= &(*p
)->next
;
1248 LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1249 browser
->ClientMachPort
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
1252 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1254 mStatus err
= mStatus_NoError
;
1255 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1257 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1259 if (SameDomainName(&ptr
->q
.qname
, d
))
1260 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1263 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1264 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1265 AssignDomainName(&question
->domain
, d
);
1266 question
->next
= browser
->qlist
;
1267 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1268 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1270 browser
->qlist
= question
;
1273 LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1274 freeL("DNSServiceBrowserQuestion", question
);
1279 mDNSexport
void machserver_automatic_browse_domain_changed(const domainname
*d
, mDNSBool add
)
1281 DNSServiceBrowser
*ptr
;
1282 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1284 if (ptr
->DefaultDomain
)
1288 mStatus err
= AddDomainToBrowser(ptr
, d
);
1289 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1293 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1296 if (SameDomainName(&(*q
)->domain
, d
))
1298 DNSServiceBrowserQuestion
*rem
= *q
;
1300 mDNS_StopQueryWithRemoves(&mDNSStorage
, &rem
->q
);
1301 freeL("DNSServiceBrowserQuestion", rem
);
1306 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1312 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1313 DNSCString regtype
, DNSCString domain
)
1315 // Check client parameter
1316 (void)unusedserver
; // Unused
1317 mStatus err
= mStatus_NoError
;
1318 const char *errormsg
= "Unknown";
1320 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1321 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1323 // Check other parameters
1326 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1327 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1328 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1329 { errormsg
= "Bad Service SubType"; goto badparam
; }
1330 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1332 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1333 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1335 // Allocate memory, and handle failure
1336 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1337 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1339 // Set up object, and link into list
1340 AssignDomainName(&x
->type
, &t
);
1341 x
->ClientMachPort
= client
;
1345 x
->next
= DNSServiceBrowserList
;
1346 DNSServiceBrowserList
= x
;
1350 // Start browser for an explicit domain
1351 x
->DefaultDomain
= mDNSfalse
;
1352 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1353 err
= AddDomainToBrowser(x
, &d
);
1354 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1358 DNameListElem
*sdPtr
;
1359 // Start browser on all domains
1360 x
->DefaultDomain
= mDNStrue
;
1361 if (!AutoBrowseDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1362 for (sdPtr
= AutoBrowseDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1364 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1367 // only terminally bail if .local fails
1368 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1369 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1370 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1375 // Succeeded: Wrap up and return
1376 EnableDeathNotificationForClient(client
, x
);
1377 return(mStatus_NoError
);
1380 err
= mStatus_BadParamErr
;
1382 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%d)", client
, regtype
, domain
, errormsg
, err
);
1386 //*************************************************************************************************************
1387 // Resolve Service Info
1389 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1391 kern_return_t status
;
1392 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1393 NetworkInterfaceInfoOSX
*ifx
= IfindexToInterfaceInfoOSX(m
, query
->info
->InterfaceID
);
1394 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1395 struct sockaddr_storage interface
;
1396 struct sockaddr_storage address
;
1398 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1401 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1403 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1405 mDNSPlatformMemZero(&interface
, sizeof(interface
));
1406 mDNSPlatformMemZero(&address
, sizeof(address
));
1408 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1410 struct sockaddr_in
*s
= (struct sockaddr_in
*)&interface
;
1411 s
->sin_len
= sizeof(*s
);
1412 s
->sin_family
= AF_INET
;
1414 s
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1416 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1418 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1419 sin6
->sin6_len
= sizeof(*sin6
);
1420 sin6
->sin6_family
= AF_INET6
;
1421 sin6
->sin6_flowinfo
= 0;
1422 sin6
->sin6_port
= 0;
1423 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1424 sin6
->sin6_scope_id
= ifx
->scope_id
;
1427 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1429 struct sockaddr_in
*s
= (struct sockaddr_in
*)&address
;
1430 s
->sin_len
= sizeof(*s
);
1431 s
->sin_family
= AF_INET
;
1432 s
->sin_port
= query
->info
->port
.NotAnInteger
;
1433 s
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1437 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1438 sin6
->sin6_len
= sizeof(*sin6
);
1439 sin6
->sin6_family
= AF_INET6
;
1440 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1441 sin6
->sin6_flowinfo
= 0;
1442 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1443 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1446 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1447 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1448 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1449 // ASCII-1 characters are used in the C-string as boundary markers,
1450 // to indicate the boundaries between the original constituent P-strings.
1451 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1454 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1458 pstrlen
= query
->info
->TXTinfo
[i
];
1461 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1463 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1464 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1465 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1466 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1467 if (status
== MACH_SEND_TIMED_OUT
)
1468 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1471 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1472 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1474 // Check client parameter
1475 (void)unusedserver
; // Unused
1476 mStatus err
= mStatus_NoError
;
1477 const char *errormsg
= "Unknown";
1478 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1479 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1481 // Check other parameters
1483 domainname t
, d
, srv
;
1484 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1485 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1486 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1487 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1489 // Allocate memory, and handle failure
1490 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1491 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1493 // Set up object, and link into list
1494 x
->ClientMachPort
= client
;
1495 x
->i
.InterfaceID
= mDNSInterface_Any
;
1497 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1498 x
->next
= DNSServiceResolverList
;
1499 DNSServiceResolverList
= x
;
1502 LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
);
1503 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1504 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1506 // Succeeded: Wrap up and return
1507 EnableDeathNotificationForClient(client
, x
);
1508 return(mStatus_NoError
);
1511 err
= mStatus_BadParamErr
;
1513 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%d)", client
, name
, regtype
, domain
, errormsg
, err
);
1517 //*************************************************************************************************************
1520 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1522 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1525 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1527 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1529 if (result
== mStatus_NoError
)
1531 kern_return_t status
;
1532 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1533 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1534 if (status
== MACH_SEND_TIMED_OUT
)
1535 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1536 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1537 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1540 else if (result
== mStatus_NameConflict
)
1542 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1543 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1544 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1545 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1547 // On conflict for an autoname service, rename and reregister *all* autoname services
1548 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1549 mDNS_ConfigChanged(m
);
1551 else if (si
->autoname
)
1553 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1558 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1559 // of their registration in the usual way (which we will catch via client death notification).
1560 // If the Mach queue is full, we forcibly abort the client immediately.
1561 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1562 if (status
== MACH_SEND_TIMED_OUT
)
1563 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1567 else if (result
== mStatus_MemFree
)
1569 if (si
->renameonmemfree
) // We intentionally terminated registration so we could re-register with new name
1571 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1572 si
->renameonmemfree
= mDNSfalse
;
1573 si
->name
= m
->nicelabel
;
1574 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1578 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1579 DNSServiceRegistration
*r
;
1580 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1582 ServiceInstance
**sp
= &r
->regs
;
1585 if (*sp
== si
) { LogMsg("RegCallback: %##s Still in list; removing", srs
->RR_SRV
.resrec
.name
->c
); *sp
= (*sp
)->next
; break; }
1590 FreeServiceInstance(si
);
1594 else if (result
!= mStatus_NATTraversal
)
1595 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %d", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1598 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1601 ServiceInstance
*si
= NULL
;
1602 AuthRecord
*SubTypes
= NULL
;
1604 for (si
= x
->regs
; si
; si
= si
->next
)
1606 if (SameDomainName(&si
->domain
, domain
))
1607 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1610 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1611 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1613 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1614 if (!si
) return mStatus_NoMemoryErr
;
1616 si
->ClientMachPort
= x
->ClientMachPort
;
1617 si
->renameonmemfree
= mDNSfalse
;
1618 si
->autoname
= x
->autoname
;
1619 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1620 si
->domain
= *domain
;
1622 err
= mDNS_RegisterService(&mDNSStorage
, &si
->srs
, &si
->name
, &x
->type
, domain
, NULL
,
1623 x
->port
, x
->txtinfo
, x
->txt_len
, SubTypes
, x
->NumSubTypes
, mDNSInterface_Any
, RegCallback
, si
);
1631 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1632 freeL("ServiceInstance", si
);
1637 mDNSexport
void machserver_automatic_registration_domain_changed(const domainname
*d
, mDNSBool add
)
1639 DNSServiceRegistration
*reg
;
1641 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1643 if (reg
->DefaultDomain
)
1646 AddServiceInstance(reg
, d
);
1649 ServiceInstance
**si
= ®
->regs
;
1652 if (SameDomainName(&(*si
)->domain
, d
))
1654 ServiceInstance
*s
= *si
;
1656 if (mDNS_DeregisterService(&mDNSStorage
, &s
->srs
)) FreeServiceInstance(s
); // only free memory synchronously on error
1661 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1667 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1668 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1670 (void)unusedserver
; // Unused
1671 mStatus err
= mStatus_NoError
;
1672 const char *errormsg
= "Unknown";
1674 // older versions of this code passed the port via mach IPC as an int.
1675 // we continue to pass it as 4 bytes to maintain binary compatibility,
1676 // but now ensure that the network byte order is preserved by using a struct
1678 port
.b
[0] = IpPort
.bytes
[2];
1679 port
.b
[1] = IpPort
.bytes
[3];
1681 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1682 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1684 // Check for sub-types after the service type
1685 size_t reglen
= strlen(regtype
) + 1;
1686 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1687 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1688 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1690 // Check other parameters
1694 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1695 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1696 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1697 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1698 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1700 unsigned char txtinfo
[1024] = "";
1701 unsigned int data_len
= 0;
1702 unsigned int size
= sizeof(RDataBody
);
1703 unsigned char *pstring
= &txtinfo
[data_len
];
1704 char *ptr
= txtRecord
;
1706 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1707 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1708 // Hence we have to convert the C-string to a P-string.
1709 // ASCII-1 characters are allowed in the C-string as boundary markers,
1710 // so that a single C-string can be used to represent one or more P-strings.
1713 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1714 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1716 pstring
= &txtinfo
[data_len
];
1722 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1723 pstring
[++pstring
[0]] = *ptr
++;
1728 if (size
< data_len
)
1731 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1732 // a port number of zero. When two instances of the protected client are allowed to run on one
1733 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1734 if (!mDNSIPPortIsZero(port
))
1736 int count
= CountExistingRegistrations(&srv
, port
);
1738 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1739 client
, count
+1, srv
.c
, mDNSVal16(port
));
1742 // Allocate memory, and handle failure
1743 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1744 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1745 mDNSPlatformMemZero(x
, sizeof(*x
));
1747 // Set up object, and link into list
1748 x
->ClientMachPort
= client
;
1749 x
->DefaultDomain
= !domain
[0];
1750 x
->autoname
= (!name
[0]);
1752 x
->NumSubTypes
= NumSubTypes
;
1753 memcpy(x
->regtype
, regtype
, reglen
);
1757 memcpy(x
->txtinfo
, txtinfo
, 1024);
1758 x
->txt_len
= data_len
;
1762 x
->next
= DNSServiceRegistrationList
;
1763 DNSServiceRegistrationList
= x
;
1765 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1766 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1768 err
= AddServiceInstance(x
, &d
);
1769 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1771 if (x
->DefaultDomain
)
1774 for (p
= AutoRegistrationDomains
; p
; p
= p
->next
)
1775 AddServiceInstance(x
, &p
->name
);
1778 // Succeeded: Wrap up and return
1779 EnableDeathNotificationForClient(client
, x
);
1780 return(mStatus_NoError
);
1783 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1785 err
= mStatus_BadParamErr
;
1787 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%d)",
1788 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1792 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1795 if (result
== mStatus_NoError
)
1797 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
1798 LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
1799 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1800 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1802 else if (result
== mStatus_NameConflict
)
1804 LogInfo("Local Hostname conflict for \"%#s.local\"", m
->hostlabel
.c
);
1805 if (!m
->p
->HostNameConflict
) m
->p
->HostNameConflict
= NonZeroTime(m
->timenow
);
1806 else if (m
->timenow
- m
->p
->HostNameConflict
> 60 * mDNSPlatformOneSecond
)
1808 // Tell the helper we've given up
1809 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, NULL
);
1812 else if (result
== mStatus_GrowCache
)
1814 // Allocate another chunk of cache storage
1815 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1816 //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
1817 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1819 else if (result
== mStatus_ConfigChanged
)
1821 // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
1822 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
1823 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
1825 // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
1826 DNSServiceRegistration
*r
;
1827 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1830 ServiceInstance
*si
;
1831 for (si
= r
->regs
; si
; si
= si
->next
)
1833 if (!SameDomainLabelCS(si
->name
.c
, m
->nicelabel
.c
))
1835 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1836 si
->renameonmemfree
= mDNStrue
;
1837 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1838 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1843 // Then we call into the UDS daemon code, to let it do the same
1844 udsserver_handle_configchange(m
);
1848 //*************************************************************************************************************
1849 // Add / Update / Remove records from existing Registration
1851 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1852 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1854 // Check client parameter
1856 mStatus err
= mStatus_NoError
;
1857 const char *errormsg
= "Unknown";
1858 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1859 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1860 ServiceInstance
*si
;
1862 (void)unusedserver
; // Unused
1863 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1864 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1866 // Check other parameters
1867 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1868 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1869 else size
= sizeof(RDataBody
);
1872 *reference
= (natural_t
)id
;
1873 for (si
= x
->regs
; si
; si
= si
->next
)
1875 // Allocate memory, and handle failure
1876 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1877 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1879 // Fill in type, length, and data of new record
1880 extra
->r
.resrec
.rrtype
= type
;
1881 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1882 extra
->r
.resrec
.rdlength
= data_len
;
1883 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1886 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1887 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1888 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1892 freeL("Extra Resource Record", extra
);
1893 errormsg
= "mDNS_AddRecordToService";
1897 extra
->ClientID
= id
;
1900 return mStatus_NoError
;
1903 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%d)", client
, x
? x
->name
.c
: (mDNSu8
*)"\x8""«NULL»", type
, data_len
, errormsg
, err
);
1904 return mStatus_UnknownErr
;
1907 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1910 if (OldRData
!= &rr
->rdatastorage
)
1911 freeL("Old RData", OldRData
);
1914 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1916 // Check client parameter
1917 mStatus err
= mStatus_NoError
;
1918 const char *errormsg
= "Unknown";
1919 const domainname
*name
= (const domainname
*)"";
1921 name
= srs
->RR_SRV
.resrec
.name
;
1923 unsigned int size
= sizeof(RDataBody
);
1924 if (size
< data_len
)
1927 // Allocate memory, and handle failure
1928 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1929 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1931 // Fill in new length, and data
1932 newrdata
->MaxRDLength
= size
;
1933 memcpy(&newrdata
->u
, data
, data_len
);
1935 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1936 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1937 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1938 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
1941 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1942 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1944 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1947 errormsg
= "mDNS_Update";
1948 freeL("RData", newrdata
);
1951 return(mStatus_NoError
);
1954 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%d)", client
, name
->c
, data_len
, errormsg
, err
);
1958 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1959 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1961 // Check client parameter
1962 mStatus err
= mStatus_NoError
;
1963 const char *errormsg
= "Unknown";
1964 const domainname
*name
= (const domainname
*)"";
1965 ServiceInstance
*si
;
1967 (void)unusedserver
; // unused
1968 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1969 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1970 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1971 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1973 // Check other parameters
1974 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1976 for (si
= x
->regs
; si
; si
= si
->next
)
1978 AuthRecord
*r
= NULL
;
1980 // Find the record we're updating. NULL reference means update the primary TXT record
1981 if (!reference
) r
= &si
->srs
.RR_TXT
;
1984 ExtraResourceRecord
*ptr
;
1985 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
1987 if ((natural_t
)ptr
->ClientID
== reference
)
1988 { r
= &ptr
->r
; break; }
1990 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1992 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
1993 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
1996 return mStatus_NoError
;
1999 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%d)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
2003 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
2005 const domainname
*const name
= srs
->RR_SRV
.resrec
.name
;
2006 mStatus err
= mStatus_NoError
;
2009 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
2011 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
2012 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
2017 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2018 natural_t reference
)
2020 // Check client parameter
2021 (void)unusedserver
; // Unused
2022 mStatus err
= mStatus_NoError
;
2023 const char *errormsg
= "Unknown";
2024 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2025 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2026 ServiceInstance
*si
;
2028 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2029 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2031 for (si
= x
->regs
; si
; si
= si
->next
)
2033 ExtraResourceRecord
*e
;
2034 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
2036 if ((natural_t
)e
->ClientID
== reference
)
2038 err
= RemoveRecord(&si
->srs
, e
, client
);
2042 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
2045 return mStatus_NoError
;
2048 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%d)", client
, reference
, errormsg
, err
);
2052 //*************************************************************************************************************
2053 #if COMPILER_LIKES_PRAGMA_MARK
2055 #pragma mark - Startup, shutdown, and supporting code
2058 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2060 mig_reply_error_t
*request
= msg
;
2061 mig_reply_error_t
*reply
;
2062 mach_msg_return_t mr
;
2064 (void)port
; // Unused
2065 (void)size
; // Unused
2066 (void)info
; // Unused
2068 KQueueLock(&mDNSStorage
);
2070 /* allocate a reply buffer */
2071 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
2073 /* call the MiG server routine */
2074 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
2076 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
2078 if (reply
->RetCode
== MIG_NO_REPLY
)
2081 * This return code is a little tricky -- it appears that the
2082 * demux routine found an error of some sort, but since that
2083 * error would not normally get returned either to the local
2084 * user or the remote one, we pretend it's ok.
2086 CFAllocatorDeallocate(NULL
, reply
);
2091 * destroy any out-of-line data in the request buffer but don't destroy
2092 * the reply port right (since we need that to send an error message).
2094 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2095 mach_msg_destroy(&request
->Head
);
2098 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2100 /* no reply port, so destroy the reply */
2101 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2102 mach_msg_destroy(&reply
->Head
);
2103 CFAllocatorDeallocate(NULL
, reply
);
2110 * We don't want to block indefinitely because the client
2111 * isn't receiving messages from the reply port.
2112 * If we have a send-once right for the reply port, then
2113 * this isn't a concern because the send won't block.
2114 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2115 * To avoid falling off the kernel's fast RPC path unnecessarily,
2116 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2119 options
= MACH_SEND_MSG
;
2120 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2121 options
|= MACH_SEND_TIMEOUT
;
2123 mr
= mach_msg(&reply
->Head
, /* msg */
2124 options
, /* option */
2125 reply
->Head
.msgh_size
, /* send_size */
2127 MACH_PORT_NULL
, /* rcv_name */
2128 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2129 MACH_PORT_NULL
); /* notify */
2131 /* Has a message error occurred? */
2134 case MACH_SEND_INVALID_DEST
:
2135 case MACH_SEND_TIMED_OUT
:
2136 /* the reply can't be delivered, so destroy it */
2137 mach_msg_destroy(&reply
->Head
);
2141 /* Includes success case. */
2145 CFAllocatorDeallocate(NULL
, reply
);
2148 KQueueUnlock(&mDNSStorage
, "Mach client event");
2151 mDNSlocal kern_return_t
registerBootstrapService()
2153 kern_return_t status
;
2154 mach_port_t service_send_port
, service_rcv_port
;
2156 debugf("Registering Bootstrap Service");
2159 * See if our service name is already registered and if we have privilege to check in.
2161 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2162 if (status
== KERN_SUCCESS
)
2165 * If so, we must be a followup instance of an already defined server. In that case,
2166 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2167 * that in case we have to unregister later (which requires the privilege port).
2169 server_priv_port
= bootstrap_port
;
2170 restarting_via_mach_init
= TRUE
;
2172 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2174 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2175 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2176 if (status
!= KERN_SUCCESS
) return status
;
2178 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2179 if (status
!= KERN_SUCCESS
)
2181 mach_port_deallocate(mach_task_self(), server_priv_port
);
2185 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2186 if (status
!= KERN_SUCCESS
)
2188 mach_port_deallocate(mach_task_self(), server_priv_port
);
2189 mach_port_deallocate(mach_task_self(), service_send_port
);
2192 assert(service_send_port
== service_rcv_port
);
2196 * We have no intention of responding to requests on the service port. We are not otherwise
2197 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2198 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2199 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2201 mach_port_destroy(mach_task_self(), service_rcv_port
);
2205 mDNSlocal kern_return_t
destroyBootstrapService()
2207 debugf("Destroying Bootstrap Service");
2208 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2211 mDNSlocal
void ExitCallback(int sig
)
2213 (void)sig
; // Unused
2214 LogMsg("%s stopping", mDNSResponderVersionString
);
2216 debugf("ExitCallback");
2217 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2218 destroyBootstrapService();
2220 debugf("ExitCallback: Aborting MIG clients");
2221 while (DNSServiceDomainEnumerationList
)
2222 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2223 while (DNSServiceBrowserList
)
2224 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2225 while (DNSServiceResolverList
)
2226 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2227 while (DNSServiceRegistrationList
)
2228 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2230 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2232 debugf("ExitCallback: mDNS_StartExit");
2233 mDNS_StartExit(&mDNSStorage
);
2236 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2237 mDNSlocal
void HandleSIG(int sig
)
2239 // WARNING: can't call syslog or fprintf from signal handler
2240 mach_msg_header_t header
;
2241 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2242 header
.msgh_remote_port
= signal_port
;
2243 header
.msgh_local_port
= MACH_PORT_NULL
;
2244 header
.msgh_size
= sizeof(header
);
2245 header
.msgh_id
= sig
;
2246 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2247 if (sig
== SIGTERM
|| sig
== SIGINT
) exit(-1);
2250 mDNSlocal
void CatchABRT(int sig
)
2252 // WARNING: can't call syslog or fprintf from signal handler
2253 // We want a CrashReporter stack trace so we can find out what library called abort()
2254 // So that we will crash, unblock all signals (that abort() may have blocked)
2257 sigprocmask(SIG_UNBLOCK
, &mask
, NULL
);
2259 while(1) *(long*)0 = 0;
2262 mDNSlocal
void INFOCallback(void)
2264 mDNSs32 utc
= mDNSPlatformUTC();
2265 DNSServiceDomainEnumeration
*e
;
2266 DNSServiceBrowser
*b
;
2267 DNSServiceResolver
*l
;
2268 DNSServiceRegistration
*r
;
2269 NetworkInterfaceInfoOSX
*i
;
2272 LogMsg("---- BEGIN STATE LOG ----");
2274 udsserver_info(&mDNSStorage
);
2276 LogMsgNoIdent("--------- Mach Clients ---------");
2277 if (!DNSServiceDomainEnumerationList
&& !DNSServiceBrowserList
&& !DNSServiceResolverList
&& !DNSServiceRegistrationList
)
2278 LogMsgNoIdent("<None>");
2281 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2282 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2284 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2286 DNSServiceBrowserQuestion
*qptr
;
2287 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2288 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2290 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2291 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2293 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2295 ServiceInstance
*si
;
2296 for (si
= r
->regs
; si
; si
= si
->next
)
2297 LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si
->ClientMachPort
, si
->srs
.RR_SRV
.resrec
.name
->c
, mDNSVal16(si
->srs
.RR_SRV
.resrec
.rdata
->u
.srv
.port
));
2301 LogMsgNoIdent("----- KQSocketEventSources -----");
2302 if (!gEventSources
) LogMsgNoIdent("<None>");
2305 KQSocketEventSource
*k
;
2306 for (k
= gEventSources
; k
; k
=k
->next
)
2307 LogMsgNoIdent("%3d %s", k
->fd
, k
->kqs
.KQtask
);
2310 LogMsgNoIdent("------ Network Interfaces ------");
2311 if (!mDNSStorage
.p
->InterfaceList
) LogMsgNoIdent("<None>");
2314 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2316 // Allow six characters for interface name, for names like "vmnet8"
2318 LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds",
2319 i
->ifinfo
.InterfaceID
,
2320 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifinfo
.ifname
, i
->scope_id
, &i
->ifinfo
.MAC
, &i
->BSSID
,
2321 &i
->ifinfo
.ip
, utc
- i
->LastSeen
);
2324 const CacheRecord
*sps
[3];
2325 FindSPSInCache(&mDNSStorage
, &i
->ifinfo
.NetWakeBrowse
, sps
);
2326 LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %s %s %-15.4a %s %s %s %s %#a",
2327 i
->ifinfo
.InterfaceID
,
2328 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifinfo
.ifname
, i
->scope_id
, &i
->ifinfo
.MAC
, &i
->BSSID
,
2329 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2330 i
->ifinfo
.IPv4Available
? "v4" : " ",
2331 i
->ifinfo
.IPv4Available
? (mDNSv4Addr
*)&i
->ifa_v4addr
: &zerov4Addr
,
2332 i
->ifinfo
.IPv6Available
? "v6" : " ",
2333 i
->ifinfo
.Advertise
? "⊙" : " ",
2334 i
->ifinfo
.McastTxRx
? "⇆" : " ",
2335 !(i
->ifinfo
.InterfaceActive
&& i
->ifinfo
.NetWake
) ? " " : !sps
[0] ? "☼" : "☀",
2338 if (sps
[0]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps
[0]->resrec
.rdata
->u
.name
.c
), sps
[0]->resrec
.rdata
->u
.name
.c
);
2339 if (sps
[1]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps
[1]->resrec
.rdata
->u
.name
.c
), sps
[1]->resrec
.rdata
->u
.name
.c
);
2340 if (sps
[2]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps
[2]->resrec
.rdata
->u
.name
.c
), sps
[2]->resrec
.rdata
->u
.name
.c
);
2345 LogMsgNoIdent("--------- DNS Servers ----------");
2346 if (!mDNSStorage
.DNSServers
) LogMsgNoIdent("<None>");
2349 for (s
= mDNSStorage
.DNSServers
; s
; s
= s
->next
)
2351 NetworkInterfaceInfoOSX
*ifx
= IfindexToInterfaceInfoOSX(&mDNSStorage
, s
->interface
);
2352 LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s",
2353 s
->domain
.c
, ifx
? ifx
->ifinfo
.ifname
: "", ifx
? " " : "", &s
->addr
, mDNSVal16(s
->port
),
2354 s
->penaltyTime
? s
->penaltyTime
- mDNS_TimeNow(&mDNSStorage
) : 0,
2355 s
->teststate
== DNSServer_Untested
? "(Untested)" :
2356 s
->teststate
== DNSServer_Passed
? "" :
2357 s
->teststate
== DNSServer_Failed
? "(Failed)" :
2358 s
->teststate
== DNSServer_Disabled
? "(Disabled)" : "(Unknown state)");
2362 mDNSs32 now
= mDNS_TimeNow(&mDNSStorage
);
2363 LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32
)now
, now
);
2365 LogMsg("---- END STATE LOG ----");
2368 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2370 (void)port
; // Unused
2371 (void)size
; // Unused
2372 (void)info
; // Unused
2373 mach_msg_header_t
*msg_header
= (mach_msg_header_t
*)msg
;
2374 mDNS
*const m
= &mDNSStorage
;
2376 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
2378 switch(msg_header
->msgh_id
)
2384 LogMsg("SIGHUP: Purge cache");
2386 FORALL_CACHERECORDS(slot
, cg
, rr
) mDNS_PurgeCacheResourceRecord(m
, rr
);
2387 // Restart unicast and multicast queries
2388 mDNSCoreRestartQueries(m
);
2392 case SIGTERM
: ExitCallback(msg_header
->msgh_id
); break;
2393 case SIGINFO
: INFOCallback(); break;
2394 case SIGUSR1
: mDNS_LoggingEnabled
= mDNS_LoggingEnabled
? 0 : 1;
2395 LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled
? "Enabled" : "Disabled");
2396 WatchDogReportingThreshold
= mDNS_LoggingEnabled
? 50 : 250;
2398 case SIGUSR2
: mDNS_PacketLoggingEnabled
= mDNS_PacketLoggingEnabled
? 0 : 1;
2399 LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled
? "Enabled" : "Disabled");
2401 default: LogMsg("SignalCallback: Unknown signal %d", msg_header
->msgh_id
); break;
2403 KQueueUnlock(m
, "Unix Signal");
2406 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2407 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2409 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2412 CFMachPortRef s_port
;
2414 // If launchd already created our Mach port for us, then use that, else we create a new one of our own
2415 if (m_port
!= MACH_PORT_NULL
)
2416 s_port
= CFMachPortCreateWithPort(NULL
, m_port
, DNSserverCallback
, NULL
, NULL
);
2419 s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2420 m_port
= CFMachPortGetPort(s_port
);
2421 char *MachServerName
= OSXVers
< OSXVers_10_3_Panther
? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2422 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2427 LogMsg("bootstrap_register() failed: A copy of the daemon is apparently already running");
2429 LogMsg("bootstrap_register() failed: %s %d", mach_error_string(status
), status
);
2434 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2435 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2436 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2437 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2438 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2440 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2441 rrcachestorage
, RR_CACHE_SIZE
,
2443 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2445 if (err
) { LogMsg("Daemon start: mDNS_Init failed %d", err
); return(err
); }
2447 client_death_port
= CFMachPortGetPort(d_port
);
2448 signal_port
= CFMachPortGetPort(i_port
);
2450 CFRunLoopAddSource(PlatformStorage
.CFRunLoop
, d_rls
, kCFRunLoopDefaultMode
);
2451 CFRunLoopAddSource(PlatformStorage
.CFRunLoop
, s_rls
, kCFRunLoopDefaultMode
);
2452 CFRunLoopAddSource(PlatformStorage
.CFRunLoop
, i_rls
, kCFRunLoopDefaultMode
);
2456 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2460 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2462 mDNSs32 now
= mDNS_TimeNow(m
);
2464 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2466 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2467 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2468 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2469 // we then systematically lose our own looped-back packets.
2470 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2472 if (m
->p
->RequestReSleep
&& now
- m
->p
->RequestReSleep
>= 0) { m
->p
->RequestReSleep
= 0; mDNSPowerRequest(0, 0); }
2474 // KeyChain frequently fails to notify clients of change events. To work around this
2475 // we set a timer and periodically poll to detect if any changes have occurred.
2476 // Without this Back To My Mac just does't work for a large number of users.
2477 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
2478 if (m
->p
->KeyChainBugTimer
&& now
- m
->p
->KeyChainBugTimer
>= 0)
2480 m
->p
->KeyChainBugInterval
*= 2;
2481 m
->p
->KeyChainBugTimer
= NonZeroTime(now
+ m
->p
->KeyChainBugInterval
);
2482 if (m
->p
->KeyChainBugInterval
> 2 * mDNSPlatformOneSecond
) m
->p
->KeyChainBugTimer
= 0;
2484 SetDomainSecrets(m
);
2488 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2489 mDNSs32 nextevent
= mDNS_Execute(m
);
2491 if (m
->p
->NetworkChanged
)
2492 if (nextevent
- m
->p
->NetworkChanged
> 0)
2493 nextevent
= m
->p
->NetworkChanged
;
2495 if (m
->p
->KeyChainBugTimer
)
2496 if (nextevent
- m
->p
->KeyChainBugTimer
> 0)
2497 nextevent
= m
->p
->KeyChainBugTimer
;
2499 if (m
->p
->RequestReSleep
)
2500 if (nextevent
- m
->p
->RequestReSleep
> 0)
2501 nextevent
= m
->p
->RequestReSleep
;
2503 // 3. Deliver any waiting browse messages to clients
2504 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2508 // Note: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2509 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2510 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2511 DNSServiceBrowser
*x
= b
;
2513 if (x
->results
) // Try to deliver the list of results
2517 DNSServiceBrowserResult
*const r
= x
->results
;
2519 domainname type
, domain
;
2520 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2521 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2522 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2523 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2524 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2525 ConvertDomainNameToCString(&type
, ctype
);
2526 ConvertDomainNameToCString(&domain
, cdom
);
2527 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2528 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2529 // If we failed to send the mach message, try again in one second
2530 if (status
== MACH_SEND_TIMED_OUT
)
2532 if (nextevent
- now
> mDNSPlatformOneSecond
)
2533 nextevent
= now
+ mDNSPlatformOneSecond
;
2538 x
->lastsuccess
= now
;
2539 x
->results
= x
->results
->next
;
2540 freeL("DNSServiceBrowserResult", r
);
2543 // If this client hasn't read a single message in the last 60 seconds, abort it
2544 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2545 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2549 DNSServiceResolver
*l
;
2550 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2551 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2554 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2555 "This places considerable burden on the network.", l
->i
.name
.c
);
2558 if (m
->p
->NotifyUser
)
2560 if (m
->p
->NotifyUser
- now
< 0)
2562 if (!SameDomainLabelCS(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2564 LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2565 mDNSPreferencesSetName(kmDNSComputerName
, &m
->p
->usernicelabel
, &m
->nicelabel
);
2566 m
->p
->usernicelabel
= m
->nicelabel
;
2568 if (!SameDomainLabelCS(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2570 LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2571 mDNSPreferencesSetName(kmDNSLocalHostName
, &m
->p
->userhostlabel
, &m
->hostlabel
);
2572 m
->p
->HostNameConflict
= 0; // Clear our indicator, now name change has been successful
2573 m
->p
->userhostlabel
= m
->hostlabel
;
2575 m
->p
->NotifyUser
= 0;
2578 if (nextevent
- m
->p
->NotifyUser
> 0)
2579 nextevent
= m
->p
->NotifyUser
;
2585 // Right now we consider *ALL* of our DHCP leases
2586 // It might make sense to be a bit more selective and only consider the leases on interfaces
2587 // (a) that are capable and enabled for wake-on-LAN, and
2588 // (b) where we have found (and successfully registered with) a Sleep Proxy
2589 // If we can't be woken for traffic on a given interface, then why keep waking to renew its lease?
2590 mDNSlocal mDNSu32
DHCPWakeTime(void)
2592 mDNSu32 e
= 24 * 3600; // Maximum maintenance wake interval is 24 hours
2593 const CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
2594 if (!now
) LogMsg("DHCPWakeTime: CFAbsoluteTimeGetCurrent failed");
2597 const SCPreferencesRef prefs
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder:DHCPWakeTime"), NULL
);
2598 if (!prefs
) LogMsg("DHCPWakeTime: SCPreferencesCreate failed");
2601 const SCNetworkSetRef currentset
= SCNetworkSetCopyCurrent(prefs
);
2602 if (!currentset
) LogMsg("DHCPWakeTime: SCNetworkSetCopyCurrent failed");
2605 const CFArrayRef services
= SCNetworkSetCopyServices(currentset
);
2606 if (!services
) LogMsg("DHCPWakeTime: SCNetworkSetCopyServices failed");
2610 for (i
= 0; i
< CFArrayGetCount(services
); i
++)
2612 const SCNetworkServiceRef service
= CFArrayGetValueAtIndex(services
, i
);
2613 if (!service
) LogMsg("DHCPWakeTime: CFArrayGetValueAtIndex %d failed", i
);
2616 const CFStringRef serviceid
= SCNetworkServiceGetServiceID(service
);
2617 if (!serviceid
) LogMsg("DHCPWakeTime: SCNetworkServiceGetServiceID %d failed", i
);
2620 // Note: It's normal for this call to return NULL, for interfaces not using DHCP
2621 const CFDictionaryRef dhcp
= SCDynamicStoreCopyDHCPInfo(NULL
, serviceid
);
2624 const CFDateRef start
= DHCPInfoGetLeaseStartTime(dhcp
);
2625 const CFDataRef lease
= DHCPInfoGetOptionData(dhcp
, 51); // Option 51 = IP Address Lease Time
2626 if (!start
|| !lease
|| CFDataGetLength(lease
) < 4)
2627 LogMsg("DHCPWakeTime: SCDynamicStoreCopyDHCPInfo index %d failed "
2628 "CFDateRef start %p CFDataRef lease %p CFDataGetLength(lease) %d",
2629 i
, start
, lease
, lease
? CFDataGetLength(lease
) : 0);
2632 const UInt8
*d
= CFDataGetBytePtr(lease
);
2633 if (!d
) LogMsg("DHCPWakeTime: CFDataGetBytePtr %d failed", i
);
2636 const mDNSu32 elapsed
= now
- CFDateGetAbsoluteTime(start
);
2637 const mDNSu32 lifetime
= (mDNSs32
) ((mDNSs32
)d
[0] << 24 | (mDNSs32
)d
[1] << 16 | (mDNSs32
)d
[2] << 8 | d
[3]);
2638 const mDNSu32 remaining
= lifetime
- elapsed
;
2639 const mDNSu32 wake
= remaining
> 60 ? remaining
- remaining
/10 : 54; // Wake at 90% of the lease time
2640 LogSPS("DHCP Address Lease Elapsed %6u Lifetime %6u Remaining %6u Wake %6u", elapsed
, lifetime
, remaining
, wake
);
2641 if (e
> wake
) e
= wake
;
2649 CFRelease(services
);
2651 CFRelease(currentset
);
2659 // We deliberately schedule our wakeup for halfway between when we'd *like* it and when we *need* it.
2660 // For example, if our DHCP lease expires in two hours, we'll typically renew it at the halfway point, after one hour.
2661 // If we scheduled our wakeup for the one-hour renewal time, that might be just seconds from now, and sleeping
2662 // for a few seconds and then waking again is silly and annoying.
2663 // If we scheduled our wakeup for the two-hour expiry time, and we were slow to wake, we might lose our lease.
2664 // Scheduling our wakeup for halfway in between -- 90 minutes -- avoids short wakeups while still
2665 // allowing us an adequate safety margin to renew our lease before we lose it.
2667 mDNSlocal mDNSBool
AllowSleepNow(mDNS
*const m
, mDNSs32 now
)
2669 mDNSBool ready
= mDNSCoreReadyForSleep(m
, now
);
2670 if (m
->SleepState
&& !ready
&& now
- m
->SleepLimit
< 0) return(mDNSfalse
);
2672 m
->p
->WakeAtUTC
= 0;
2673 int result
= kIOReturnSuccess
;
2674 CFDictionaryRef opts
= NULL
;
2676 // If the sleep request was cancelled, and we're no longer planning to sleep, don't need to
2677 // do the stuff below, but we *DO* still need to acknowledge the sleep message we received.
2679 LogMsg("AllowSleepNow: Sleep request was canceled with %d ticks remaining", m
->SleepLimit
- now
);
2682 if (!m
->SystemWakeOnLANEnabled
|| !mDNSCoreHaveAdvertisedMulticastServices(m
))
2683 LogSPS("AllowSleepNow: Not scheduling wakeup: SystemWakeOnLAN %s enabled; %s advertised services",
2684 m
->SystemWakeOnLANEnabled
? "is" : "not",
2685 mDNSCoreHaveAdvertisedMulticastServices(m
) ? "have" : "no");
2688 mDNSs32 dhcp
= DHCPWakeTime();
2689 LogSPS("ComputeWakeTime: DHCP Wake %d", dhcp
);
2690 mDNSs32 interval
= mDNSCoreIntervalToNextWake(m
, now
) / mDNSPlatformOneSecond
;
2691 if (interval
> dhcp
) interval
= dhcp
;
2693 // If we're not ready to sleep (failed to register with Sleep Proxy, maybe because of
2694 // transient network problem) then schedule a wakeup in one hour to try again. Otherwise,
2695 // a single SPS failure could result in a remote machine falling permanently asleep, requiring
2696 // someone to go to the machine in person to wake it up again, which would be unacceptable.
2697 if (!ready
&& interval
> 3600) interval
= 3600;
2699 //interval = 48; // For testing
2701 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
2702 if (m
->p
->IOPMConnection
) // If lightweight-wake capability is available, use that
2704 const CFDateRef WakeDate
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
2705 if (!WakeDate
) LogMsg("ScheduleNextWake: CFDateCreate failed");
2708 const mDNSs32 reqs
= kIOPMSystemPowerStateCapabilityNetwork
;
2709 const CFNumberRef Requirements
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &reqs
);
2710 if (!Requirements
) LogMsg("ScheduleNextWake: CFNumberCreate failed");
2713 const void *OptionKeys
[2] = { CFSTR("WakeDate"), CFSTR("Requirements") };
2714 const void *OptionVals
[2] = { WakeDate
, Requirements
};
2715 opts
= CFDictionaryCreate(NULL
, (void*)OptionKeys
, (void*)OptionVals
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2716 if (!opts
) LogMsg("ScheduleNextWake: CFDictionaryCreate failed");
2717 CFRelease(Requirements
);
2719 CFRelease(WakeDate
);
2721 LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval
);
2723 else // else schedule the wakeup using the old API instead to
2726 // If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us,
2727 // so we should put it back to sleep. To avoid frustrating the user, we always request at least
2728 // 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep,
2729 // we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine.
2730 if (interval
< 60) interval
= 60;
2732 result
= mDNSPowerRequest(1, interval
);
2734 if (result
== kIOReturnNotReady
)
2736 LogMsg("Requested wakeup in %d seconds unsuccessful; retrying with longer intervals", interval
);
2737 // IOPMSchedulePowerEvent fails with kIOReturnNotReady (-536870184/0xe00002d8) if the
2738 // requested wake time is "too soon", but there's no API to find out what constitutes
2739 // "too soon" on any given OS/hardware combination, so if we get kIOReturnNotReady
2740 // we just have to iterate with successively longer intervals until it doesn't fail.
2741 // Additionally, if our power request is deemed "too soon" for the machine to get to
2742 // sleep and wake back up again, we attempt to cancel the sleep request, since the
2743 // implication is that the system won't manage to be awake again at the time we need it.
2746 interval
+= (interval
< 20) ? 1 : ((interval
+3) / 4);
2747 result
= mDNSPowerRequest(1, interval
);
2749 while (result
== kIOReturnNotReady
);
2752 if (result
) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval
, result
, result
);
2753 else LogSPS("AllowSleepNow: Requested wakeup in %d seconds", interval
);
2754 m
->p
->WakeAtUTC
= mDNSPlatformUTC() + interval
;
2758 // Clear our interface list to empty state, ready to go to sleep
2759 // As a side effect of doing this, we'll also cancel any outstanding SPS Resolve calls that didn't complete
2760 m
->SleepState
= SleepState_Sleeping
;
2761 mDNSMacOSXNetworkChanged(m
);
2764 LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
2765 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
2766 (m
->p
->IOPMConnection
) ? "IOPMConnectionAcknowledgeEventWithOptions" :
2768 (result
== kIOReturnSuccess
) ? "IOAllowPowerChange" : "IOCancelPowerChange",
2769 m
->p
->SleepCookie
, ready
? "ready for sleep" : "giving up", now
, m
->SleepLimit
- now
);
2771 m
->SleepLimit
= 0; // Don't clear m->SleepLimit until after we've logged it above
2773 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
2774 if (m
->p
->IOPMConnection
) IOPMConnectionAcknowledgeEventWithOptions(m
->p
->IOPMConnection
, m
->p
->SleepCookie
, opts
);
2777 if (result
== kIOReturnSuccess
) IOAllowPowerChange (m
->p
->PowerConnection
, m
->p
->SleepCookie
);
2778 else IOCancelPowerChange(m
->p
->PowerConnection
, m
->p
->SleepCookie
);
2780 if (opts
) CFRelease(opts
);
2784 mDNSlocal
void KQWokenFlushBytes(int fd
, __unused
short filter
, __unused
void *context
)
2786 // Read all of the bytes so we won't wake again.
2788 while (recv(fd
, buffer
, sizeof(buffer
), MSG_DONTWAIT
) > 0) continue;
2791 mDNSlocal
void * KQueueLoop(void *m_param
)
2796 #if USE_SELECT_WITH_KQUEUEFD
2799 const int multiplier
= 1000000 / mDNSPlatformOneSecond
;
2801 const int multiplier
= 1000000000 / mDNSPlatformOneSecond
;
2804 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2805 LogInfo("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2807 // This is the main work loop:
2808 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2809 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2810 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2811 // (4) On wakeup we first process *all* events
2812 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2815 #define kEventsToReadAtOnce 1
2816 struct kevent new_events
[kEventsToReadAtOnce
];
2818 // Run mDNS_Execute to find out the time we next need to wake up
2819 mDNSs32 start
= mDNSPlatformRawTime();
2820 mDNSs32 nextTimerEvent
= udsserver_idle(mDNSDaemonIdle(m
));
2821 mDNSs32 end
= mDNSPlatformRawTime();
2822 if (end
- start
>= WatchDogReportingThreshold
)
2823 LogInfo("WARNING: Idle task took %dms to complete", end
- start
);
2825 mDNSs32 now
= mDNS_TimeNow(m
);
2827 if (m
->ShutdownTime
)
2829 if (mDNSStorage
.ResourceRecords
)
2831 LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m
, mDNSStorage
.ResourceRecords
));
2832 if (mDNS_LoggingEnabled
) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages
2834 if (mDNSStorage
.ServiceRegistrations
)
2835 LogInfo("Cannot exit yet; ServiceRegistrations still exists: %s", ARDisplayString(m
, &mDNSStorage
.ServiceRegistrations
->RR_SRV
));
2836 if (mDNS_ExitNow(m
, now
))
2838 if (!mDNSStorage
.ResourceRecords
&& !mDNSStorage
.ServiceRegistrations
)
2839 safe_vproc_transaction_end();
2840 LogInfo("mDNS_FinalExit");
2841 mDNS_FinalExit(&mDNSStorage
);
2842 usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
2845 if (nextTimerEvent
- m
->ShutdownTime
>= 0)
2846 nextTimerEvent
= m
->ShutdownTime
;
2850 if (!AllowSleepNow(m
, now
))
2851 if (nextTimerEvent
- m
->SleepLimit
>= 0)
2852 nextTimerEvent
= m
->SleepLimit
;
2854 // Convert absolute wakeup time to a relative time from now
2855 mDNSs32 ticks
= nextTimerEvent
- now
;
2856 if (ticks
< 1) ticks
= 1;
2858 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2864 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2867 verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2870 // Release the lock, and sleep until:
2871 // 1. Something interesting happens like a packet arriving, or
2872 // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
2873 // 3. The timeout expires
2874 pthread_mutex_unlock(&PlatformStorage
.BigMutex
);
2876 #if USE_SELECT_WITH_KQUEUEFD
2877 struct timeval timeout
;
2878 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2879 timeout
.tv_usec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2880 FD_SET(KQueueFD
, &readfds
);
2881 if (select(KQueueFD
+1, &readfds
, NULL
, NULL
, &timeout
) < 0)
2882 { LogMsg("select(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2884 struct timespec timeout
;
2885 timeout
.tv_sec
= ticks
/ mDNSPlatformOneSecond
;
2886 timeout
.tv_nsec
= (ticks
% mDNSPlatformOneSecond
) * multiplier
;
2887 // In my opinion, you ought to be able to call kevent() with nevents set to zero,
2888 // and have it work similarly to the way it does with nevents non-zero --
2889 // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
2890 // In fact, what happens if you do this is that it just returns immediately. So, we have
2891 // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
2892 if (kevent(KQueueFD
, NULL
, 0, new_events
, 1, &timeout
) < 0)
2893 { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD
, errno
, strerror(errno
)); sleep(1); }
2896 pthread_mutex_lock(&PlatformStorage
.BigMutex
);
2897 // We have to ignore the event we may have been told about above, because that
2898 // was done without holding the lock, and between the time we woke up and the
2899 // time we reclaimed the lock the other thread could have done something that
2900 // makes the event no longer valid. Now we have the lock, we call kevent again
2901 // and this time we can safely process the events it tells us about.
2903 static const struct timespec zero_timeout
= { 0, 0 };
2905 while ((events_found
= kevent(KQueueFD
, NULL
, 0, new_events
, kEventsToReadAtOnce
, &zero_timeout
)) != 0)
2907 if (events_found
> kEventsToReadAtOnce
|| (events_found
< 0 && errno
!= EINTR
))
2909 // Not sure what to do here, our kqueue has failed us - this isn't ideal
2910 LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno
, strerror(errno
));
2914 numevents
+= events_found
;
2917 for (i
= 0; i
< events_found
; i
++)
2919 const KQueueEntry
*const kqentry
= new_events
[i
].udata
;
2920 mDNSs32 stime
= mDNSPlatformRawTime();
2921 const char *const KQtask
= kqentry
->KQtask
; // Grab a copy in case KQcallback deletes the task
2922 kqentry
->KQcallback(new_events
[i
].ident
, new_events
[i
].filter
, kqentry
->KQcontext
);
2923 mDNSs32 etime
= mDNSPlatformRawTime();
2924 if (etime
- stime
>= WatchDogReportingThreshold
)
2925 LogInfo("WARNING: %s took %dms to complete", KQtask
, etime
- stime
);
2933 mDNSlocal
void LaunchdCheckin(void)
2935 launch_data_t msg
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
2936 launch_data_t resp
= launch_msg(msg
);
2937 launch_data_free(msg
);
2938 if (!resp
) { LogMsg("launch_msg returned NULL"); return; }
2940 if (launch_data_get_type(resp
) == LAUNCH_DATA_ERRNO
)
2942 int err
= launch_data_get_errno(resp
);
2943 // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
2944 if (err
!= EACCES
) LogMsg("launch_msg returned %d", err
);
2945 else LogInfo("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err
);
2949 launch_data_t skts
= launch_data_dict_lookup(resp
, LAUNCH_JOBKEY_SOCKETS
);
2950 if (!skts
) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
2953 launch_data_t skt
= launch_data_dict_lookup(skts
, "Listeners");
2954 if (!skt
) LogMsg("launch_data_dict_lookup Listeners returned NULL");
2957 launchd_fds_count
= launch_data_array_get_count(skt
);
2958 if (launchd_fds_count
== 0) LogMsg("launch_data_array_get_count(skt) returned 0");
2961 launchd_fds
= mallocL("LaunchdCheckin", sizeof(dnssd_sock_t
) * launchd_fds_count
);
2962 if (!launchd_fds
) LogMsg("LaunchdCheckin: malloc failed");
2966 for(i
= 0; i
< launchd_fds_count
; i
++)
2968 launch_data_t s
= launch_data_array_get_index(skt
, i
);
2971 launchd_fds
[i
] = dnssd_InvalidSocket
;
2972 LogMsg("launch_data_array_get_index(skt, %d) returned NULL", i
);
2976 launchd_fds
[i
] = launch_data_get_fd(s
);
2977 LogInfo("Launchd Unix Domain Socket [%d]: %d", i
, launchd_fds
[i
]);
2981 // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
2982 chmod(MDNS_UDS_SERVERPATH
, S_IRUSR
|S_IWUSR
| S_IRGRP
|S_IWGRP
| S_IROTH
|S_IWOTH
);
2987 launch_data_t ports
= launch_data_dict_lookup(resp
, "MachServices");
2988 if (!ports
) LogMsg("launch_data_dict_lookup MachServices returned NULL");
2991 launch_data_t p
= launch_data_dict_lookup(ports
, "com.apple.mDNSResponder");
2992 if (!p
) LogInfo("launch_data_dict_lookup(ports, \"com.apple.mDNSResponder\") returned NULL");
2995 m_port
= launch_data_get_fd(p
);
2996 LogInfo("Launchd Mach Port: %d", m_port
);
2997 if (m_port
== ~0U) m_port
= MACH_PORT_NULL
;
3001 launch_data_free(resp
);
3004 mDNSlocal
void DropPrivileges(void)
3006 static const char login
[] = "_mdnsresponder";
3007 struct passwd
*pwd
= getpwnam(login
);
3009 LogMsg("Could not find account name \"%s\". Running as root.", login
);
3012 uid_t uid
= pwd
->pw_uid
;
3013 gid_t gid
= pwd
->pw_gid
;
3015 LogMsg("Started as root. Switching to userid \"%s\".", login
);
3017 if (unlink(MDNS_UDS_SERVERPATH
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, errno
, strerror(errno
));
3020 static char path
[] = "/var/run/mdns/mDNSResponder";
3021 char *p
= strrchr(path
, '/');
3023 if (mkdir(path
, 0755) < 0 && errno
!= EEXIST
) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
3024 else if (chown(path
, uid
, gid
) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path
, errno
, strerror(errno
));
3028 if (unlink(path
) < 0 && errno
!= ENOENT
) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path
, errno
, strerror(errno
));
3029 else if (symlink(path
, MDNS_UDS_SERVERPATH
) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH
, path
, errno
, strerror(errno
));
3030 else LogInfo("DropPrivileges: Created subdirectory and symlink");
3034 if (0 != initgroups(login
, gid
)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login
, (unsigned long)gid
);
3035 if (0 != setgid(gid
)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid());
3036 if (0 != setuid(uid
)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid
);
3040 extern int sandbox_init(const char *profile
, uint64_t flags
, char **errorbuf
) __attribute__((weak_import
));
3042 mDNSexport
int main(int argc
, char **argv
)
3045 kern_return_t status
;
3046 pthread_t KQueueThread
;
3048 LogMsg("%s starting", mDNSResponderVersionString
);
3051 LogMsg("CacheRecord %d", sizeof(CacheRecord
));
3052 LogMsg("CacheGroup %d", sizeof(CacheGroup
));
3053 LogMsg("ResourceRecord %d", sizeof(ResourceRecord
));
3054 LogMsg("RData_small %d", sizeof(RData_small
));
3056 LogMsg("sizeof(CacheEntity) %d", sizeof(CacheEntity
));
3057 LogMsg("RR_CACHE_SIZE %d", RR_CACHE_SIZE
);
3058 LogMsg("block usage %d", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
3059 LogMsg("block wastage %d", 16*1024 - sizeof(CacheEntity
) * RR_CACHE_SIZE
);
3062 safe_vproc_transaction_begin();
3064 if (0 == geteuid()) DropPrivileges();
3066 for (i
=1; i
<argc
; i
++)
3068 if (!strcasecmp(argv
[i
], "-d" )) mDNS_DebugMode
= mDNStrue
;
3069 if (!strcasecmp(argv
[i
], "-launchd" )) started_via_launchdaemon
= mDNStrue
;
3070 if (!strcasecmp(argv
[i
], "-launchdaemon" )) started_via_launchdaemon
= mDNStrue
;
3071 if (!strcasecmp(argv
[i
], "-NoMulticastAdvertisements")) advertise
= mDNS_Init_DontAdvertiseLocalAddresses
;
3072 if (!strcasecmp(argv
[i
], "-DebugLogging" )) mDNS_LoggingEnabled
= mDNStrue
;
3073 if (!strcasecmp(argv
[i
], "-UnicastPacketLogging" )) mDNS_PacketLoggingEnabled
= mDNStrue
;
3074 if (!strcasecmp(argv
[i
], "-OfferSleepProxyService" ))
3075 OfferSleepProxyService
= (i
+1<argc
&& mDNSIsDigit(argv
[i
+1][0]) && mDNSIsDigit(argv
[i
+1][1]) && argv
[i
+1][2]==0) ? atoi(argv
[++i
]) : 80;
3076 if (!strcasecmp(argv
[i
], "-StrictUnicastOrdering" )) StrictUnicastOrdering
= mDNStrue
;
3079 // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
3080 if (!advertise
) LogMsg("Administratively prohibiting multicast advertisements");
3082 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
3084 signal(SIGHUP
, HandleSIG
); // (Debugging) Purge the cache to check for cache handling bugs
3085 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
3086 // On 10.5 and later, the default action for SIGABRT is to generate a crash report, so we only need our CatchABRT handler on 10.4
3087 if (OSXVers
<= OSXVers_10_4_Tiger
)
3089 LogInfo("Adding SIGABRT handler");
3090 signal(SIGABRT
, CatchABRT
); // For debugging -- SIGABRT should never happen
3092 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
3093 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
3094 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
3095 signal(SIGUSR1
, HandleSIG
); // (Debugging) Enable Logging
3096 signal(SIGUSR2
, HandleSIG
); // (Debugging) Enable Packet Logging
3098 mDNSStorage
.p
= &PlatformStorage
; // Make sure mDNSStorage.p is set up, because validatelists uses it
3101 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
3102 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
3104 registerBootstrapService();
3105 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
3106 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
3107 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
3110 // Avoid unnecessarily duplicating a file descriptor to itself
3111 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
3112 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
3113 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
3114 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
3118 // Create the kqueue, mutex and thread to support KQSockets
3119 KQueueFD
= kqueue();
3120 if (KQueueFD
== -1) { LogMsg("kqueue() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3122 i
= pthread_mutex_init(&PlatformStorage
.BigMutex
, NULL
);
3123 if (i
== -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3125 int fdpair
[2] = {0, 0};
3126 i
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
);
3127 if (i
== -1) { LogMsg("socketpair() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3129 // Socket pair returned us two identical sockets connected to each other
3130 // We will use the first socket to send the second socket. The second socket
3131 // will be added to the kqueue so it will wake when data is sent.
3132 static const KQueueEntry wakeKQEntry
= { KQWokenFlushBytes
, NULL
, "kqueue wakeup after CFRunLoop event" };
3133 PlatformStorage
.WakeKQueueLoopFD
= fdpair
[0];
3134 KQueueSet(fdpair
[1], EV_ADD
, EVFILT_READ
, &wakeKQEntry
);
3136 // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
3138 LogMsg("Note: Compiled without Apple Sandbox support");
3141 LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
3145 int sandbox_err
= sandbox_init("mDNSResponder", SANDBOX_NAMED
, &sandbox_msg
);
3146 if (sandbox_err
) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg
); sandbox_free_error(sandbox_msg
); }
3147 else LogInfo("Now running under Apple Sandbox restrictions");
3151 status
= mDNSDaemonInitialize();
3152 if (status
) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit
; }
3154 status
= udsserver_init(launchd_fds
, launchd_fds_count
);
3155 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
3157 mDNSMacOSXNetworkChanged(&mDNSStorage
);
3159 // Start the kqueue thread
3160 i
= pthread_create(&KQueueThread
, NULL
, KQueueLoop
, &mDNSStorage
);
3161 if (i
== -1) { LogMsg("pthread_create() failed errno %d (%s)", errno
, strerror(errno
)); status
= errno
; goto exit
; }
3166 LogMsg("ERROR: CFRunLoopRun Exiting.");
3167 mDNS_Close(&mDNSStorage
);
3170 LogMsg("%s exiting", mDNSResponderVersionString
);
3173 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
3177 // uds_daemon.c support routines /////////////////////////////////////////////
3179 // Arrange things so that when data appears on fd, callback is called with context
3180 mDNSexport mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
3182 KQSocketEventSource
**p
= &gEventSources
;
3183 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
3184 if (*p
) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd
); return mStatus_AlreadyRegistered
; }
3186 KQSocketEventSource
*newSource
= (KQSocketEventSource
*) mallocL("KQSocketEventSource", sizeof *newSource
);
3187 if (!newSource
) return mStatus_NoMemoryErr
;
3189 newSource
->next
= mDNSNULL
;
3191 newSource
->kqs
.KQcallback
= callback
;
3192 newSource
->kqs
.KQcontext
= context
;
3193 newSource
->kqs
.KQtask
= "UDS client";
3195 if (KQueueSet(fd
, EV_ADD
, EVFILT_READ
, &newSource
->kqs
) == 0)
3198 return mStatus_NoError
;
3201 LogMsg("KQueueSet failed for fd %d errno %d (%s)", fd
, errno
, strerror(errno
));
3202 freeL("KQSocketEventSource", newSource
);
3203 return mStatus_BadParamErr
;
3206 mDNSexport mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
3208 KQSocketEventSource
**p
= &gEventSources
;
3209 while (*p
&& (*p
)->fd
!= fd
) p
= &(*p
)->next
;
3212 KQSocketEventSource
*s
= *p
;
3214 // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
3215 // causes the kernel to automatically remove any associated kevents
3217 freeL("KQSocketEventSource", s
);
3218 return mStatus_NoError
;
3220 LogMsg("udsSupportRemoveFDFromEventLoop: ERROR fd %d not found in EventLoop source list", fd
);
3221 return mStatus_NoSuchNameErr
;
3224 #if _BUILDING_XCODE_PROJECT_
3225 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
3226 const char *__crashreporter_info__
= mDNSResponderVersionString
;
3227 asm(".desc ___crashreporter_info__, 0x10");
3230 // For convenience when using the "strings" command, this is the last thing in the file
3231 // The "@(#) " pattern is a special prefix the "what" command looks for
3232 mDNSexport
const char mDNSResponderVersionString_SCCS
[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";