2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
25 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
26 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
27 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
28 * therefore common sense dictates that if they are part of a compound statement then they
29 * should be indented to the same level as everything else in that compound statement.
30 * Indenting curly braces at the same level as the "if" implies that curly braces are
31 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
32 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
33 * understand why variable y is not of type "char*" just proves the point that poor code
34 * layout leads people to unfortunate misunderstandings about how the C language really works.)
36 Change History (most recent first):
39 Revision 1.260 2005/11/07 01:51:58 cheshire
40 <rdar://problem/4331591> Include list of configured DNS servers in SIGINFO output
42 Revision 1.259 2005/07/22 21:50:55 ksekar
43 Fix GCC 4.0/Intel compiler warnings
45 Revision 1.258 2005/07/04 22:40:26 cheshire
46 Additional debugging code to help catch memory corruption
48 Revision 1.257 2005/03/28 19:28:55 cheshire
49 Fix minor typos in LogOperation() messages
51 Revision 1.256 2005/03/17 22:01:22 cheshire
52 Tidy up alignment of lines to make code more readable
54 Revision 1.255 2005/03/09 00:48:43 cheshire
55 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
56 Move "m->p->NetworkChanged = 0;" line from caller to callee
58 Revision 1.254 2005/03/03 04:34:19 cheshire
59 <rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
61 Revision 1.253 2005/03/03 03:55:09 cheshire
62 <rdar://problem/3862944> Name collision notifications should be localized
64 Revision 1.252 2005/02/23 02:29:17 cheshire
65 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
66 Minor refinements, better variable names, improved comments
68 Revision 1.251 2005/02/21 21:31:24 ksekar
69 <rdar://problem/4015162> changed LogMsg to debugf
71 Revision 1.250 2005/02/19 01:25:04 cheshire
72 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
75 Revision 1.249 2005/02/19 00:28:45 cheshire
76 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
78 Revision 1.248 2005/02/19 00:18:34 cheshire
79 Confusing variable name -- alertMessage should be called alertHeader
81 Revision 1.247 2005/02/15 02:13:49 cheshire
82 If we did registerBootstrapService() when starting, then we must do
83 destroyBootstrapService() before exiting, or Mach init will keep restarting us.
85 Revision 1.246 2005/02/03 00:44:37 cheshire
86 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
88 Revision 1.245 2005/02/01 19:56:47 ksekar
89 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
91 Revision 1.244 2005/01/28 00:34:49 cheshire
92 Turn off "Starting time value" log message
94 Revision 1.243 2005/01/27 17:46:58 cheshire
95 Added comment about CFSocketInvalidate closing the underlying socket
97 Revision 1.242 2005/01/27 00:10:58 cheshire
98 <rdar://problem/3967867> Name change log messages every time machine boots
100 Revision 1.241 2005/01/25 17:28:06 ksekar
101 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
103 Revision 1.240 2005/01/21 02:39:18 cheshire
104 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
106 Revision 1.239 2005/01/20 00:25:01 cheshire
107 Improve validatelists() log message generation
109 Revision 1.238 2005/01/19 19:15:35 ksekar
110 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
112 Revision 1.237 2005/01/19 03:33:09 cheshire
113 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
115 Revision 1.236 2005/01/19 03:16:38 cheshire
116 <rdar://problem/3961051> CPU Spin in mDNSResponder
117 Improve detail of "Task Scheduling Error" diagnostic messages
119 Revision 1.235 2005/01/15 00:56:41 ksekar
120 <rdar://problem/3954575> Unicast services don't disappear when logging
123 Revision 1.234 2005/01/10 03:42:30 ksekar
126 Revision 1.233 2004/12/18 00:53:46 cheshire
127 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
129 Revision 1.232 2004/12/17 23:37:48 cheshire
130 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
131 (and other repetitive configuration changes)
133 Revision 1.231 2004/12/17 04:13:38 cheshire
134 Removed debugging check
136 Revision 1.230 2004/12/17 04:09:30 cheshire
137 <rdar://problem/3191011> Switch mDNSResponder to launchd
139 Revision 1.229 2004/12/16 21:51:36 cheshire
140 Remove some startup messages
142 Revision 1.228 2004/12/16 20:13:01 cheshire
143 <rdar://problem/3324626> Cache memory management improvements
145 Revision 1.227 2004/12/10 13:52:57 cheshire
146 <rdar://problem/3909995> Turn off SIGPIPE signals
148 Revision 1.226 2004/12/10 05:27:26 cheshire
149 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
151 Revision 1.225 2004/12/10 04:28:29 cheshire
152 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
154 Revision 1.224 2004/12/10 00:41:05 cheshire
155 Adjust alignment of log messages
157 Revision 1.223 2004/12/07 20:42:34 cheshire
158 Add explicit context parameter to mDNS_RemoveRecordFromService()
160 Revision 1.222 2004/12/06 21:15:23 ksekar
161 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
163 Revision 1.221 2004/11/30 03:24:04 cheshire
164 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
166 Revision 1.220 2004/11/29 23:34:31 cheshire
167 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
168 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
169 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
171 Revision 1.219 2004/11/25 01:00:56 cheshire
172 Checkin 1.217 not necessary
174 Revision 1.218 2004/11/24 20:27:19 cheshire
175 Add missing "err" parameter in LogMsg() call
177 Revision 1.217 2004/11/24 17:55:01 ksekar
178 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
180 Revision 1.216 2004/11/24 00:10:44 cheshire
181 <rdar://problem/3869241> For unicast operations, verify that service types are legal
183 Revision 1.215 2004/11/23 22:33:01 cheshire
184 <rdar://problem/3654910> Remove temporary workaround code for iChat
186 Revision 1.214 2004/11/23 22:13:59 cheshire
187 <rdar://problem/3886293> Subtype advertising broken for Mach API
189 Revision 1.213 2004/11/23 06:12:55 cheshire
190 <rdar://problem/3871405> Update wording for name conflict dialogs
192 Revision 1.212 2004/11/23 05:15:37 cheshire
193 <rdar://problem/3875830> Computer Name in use message garbled
195 Revision 1.211 2004/11/23 05:00:41 cheshire
196 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
198 Revision 1.210 2004/11/03 03:45:17 cheshire
199 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
201 Revision 1.209 2004/11/03 02:25:50 cheshire
202 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
204 Revision 1.208 2004/11/03 01:54:14 cheshire
205 Update debugging messages
207 Revision 1.207 2004/11/02 23:58:19 cheshire
208 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
210 Revision 1.206 2004/10/28 02:40:47 cheshire
211 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
213 Revision 1.205 2004/10/28 02:21:01 cheshire
214 <rdar://problem/3856500> Improve mDNSResponder signal handling
215 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
216 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
218 Revision 1.204 2004/10/27 01:57:21 cheshire
219 Add check of m->p->InterfaceList
221 Revision 1.203 2004/10/26 04:31:44 cheshire
222 Rename CountSubTypes() as ChopSubTypes()
224 Revision 1.202 2004/10/26 01:29:18 cheshire
225 Use "#if 0" instead of commenting out code
227 Revision 1.201 2004/10/25 21:41:39 ksekar
228 <rdar://problem/3852958> wide-area name conflicts can cause crash
230 Revision 1.200 2004/10/22 01:03:55 cheshire
231 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
232 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
234 Revision 1.199 2004/10/19 21:33:19 cheshire
235 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
236 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
237 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
239 Revision 1.198 2004/10/15 23:00:18 ksekar
240 <rdar://problem/3799242> Need to update LLQs on location changes
242 Revision 1.197 2004/10/12 23:38:59 ksekar
243 <rdar://problem/3837065> remove unnecessary log message
245 Revision 1.196 2004/10/04 05:56:04 cheshire
246 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
248 Revision 1.195 2004/09/30 00:24:59 ksekar
249 <rdar://problem/3695802> Dynamically update default registration domains on config change
251 Revision 1.194 2004/09/26 23:20:35 ksekar
252 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
254 Revision 1.193 2004/09/23 23:35:27 cheshire
257 Revision 1.192 2004/09/21 23:40:12 ksekar
258 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
260 Revision 1.191 2004/09/21 21:05:12 cheshire
261 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
262 into mDNSShared/uds_daemon.c
264 Revision 1.190 2004/09/21 19:51:15 cheshire
265 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
267 Revision 1.189 2004/09/21 18:17:23 cheshire
268 <rdar://problem/3785400> Add version info to mDNSResponder
270 Revision 1.188 2004/09/20 21:45:27 ksekar
273 Revision 1.187 2004/09/17 01:08:52 cheshire
274 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
275 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
276 declared in that file are ONLY appropriate to single-address-space embedded applications.
277 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
279 Revision 1.186 2004/09/16 00:24:49 cheshire
280 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
282 Revision 1.185 2004/08/25 02:01:45 cheshire
283 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
285 Revision 1.184 2004/08/19 19:04:12 ksekar
286 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
288 Revision 1.183 2004/08/14 03:22:42 cheshire
289 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
290 Add GetUserSpecifiedDDNSName() routine
291 Convert ServiceRegDomain to domainname instead of C string
292 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
294 Revision 1.182 2004/08/13 23:57:59 cheshire
295 Get rid of non-portable "_UNUSED"
297 Revision 1.181 2004/08/11 02:02:26 cheshire
298 Remove "mDNS *globalInstance" parameter from udsserver_init();
299 Move CheckForDuplicateRegistrations to uds_daemon.c
301 Revision 1.180 2004/07/13 21:24:25 rpantos
302 Fix for <rdar://problem/3701120>.
304 Revision 1.179 2004/06/19 00:02:54 cheshire
305 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
307 Revision 1.178 2004/06/18 19:10:00 cheshire
308 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
310 Revision 1.177 2004/06/16 23:14:46 ksekar
311 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
313 Revision 1.176 2004/06/11 20:27:42 cheshire
314 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
316 Revision 1.175 2004/06/10 20:23:21 cheshire
317 Also list interfaces in SIGINFO output
319 Revision 1.174 2004/06/08 18:54:48 ksekar
320 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
322 Revision 1.173 2004/06/08 17:35:12 cheshire
323 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
325 Revision 1.172 2004/06/05 00:04:26 cheshire
326 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
328 Revision 1.171 2004/06/04 08:58:30 ksekar
329 <rdar://problem/3668624>: Keychain integration for secure dynamic update
331 Revision 1.170 2004/05/30 20:01:50 ksekar
332 <rdar://problem/3668635>: wide-area default registrations should be in
333 .local too - fixed service registration when clients pass an explicit
334 domain (broken by previous checkin)
336 Revision 1.169 2004/05/30 01:30:16 ksekar
337 <rdar://problem/3668635>: wide-area default registrations should be in
340 Revision 1.168 2004/05/18 23:51:26 cheshire
341 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
343 Revision 1.167 2004/05/14 16:39:47 ksekar
344 Browse for iChat locally for now.
346 Revision 1.166 2004/05/13 21:33:52 ksekar
347 Clean up non-local registration control via config file. Force iChat
348 registrations to be local for now.
350 Revision 1.165 2004/05/13 04:54:20 ksekar
351 Unified list copy/free code. Added symetric list for
353 Revision 1.164 2004/05/12 22:03:08 ksekar
354 Made GetSearchDomainList a true platform-layer call (declaration moved
355 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
356 only on non-OSX platforms. Changed call to return a copy of the list
357 to avoid shared memory issues. Added a routine to free the list.
359 Revision 1.163 2004/05/12 02:03:25 ksekar
360 Non-local domains will only be browsed by default, and show up in
361 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
363 Revision 1.162 2004/04/14 23:09:29 ksekar
364 Support for TSIG signed dynamic updates.
366 Revision 1.161 2004/04/07 01:20:04 cheshire
367 Hash slot value should be unsigned
369 Revision 1.160 2004/04/06 19:51:24 cheshire
370 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
371 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
373 Revision 1.159 2004/04/03 01:36:55 cheshire
374 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
375 If "nobody" user doesn't exist, log a message and continue as "root"
377 Revision 1.158 2004/04/02 21:39:05 cheshire
378 Fix errors in comments
380 Revision 1.157 2004/03/19 18:49:10 ksekar
381 Increased size check in freeL() to account for LargeCacheRecord
382 structs larger than 8k
384 Revision 1.156 2004/03/19 18:19:19 ksekar
385 Fixed daemon.c to compile with malloc debugging turned on.
387 Revision 1.155 2004/03/13 01:57:34 ksekar
388 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
390 Revision 1.154 2004/03/12 08:42:47 cheshire
391 <rdar://problem/3548256>: Should not allow empty string for resolve domain
393 Revision 1.153 2004/03/12 08:08:51 cheshire
396 Revision 1.152 2004/02/05 19:39:29 cheshire
397 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
398 so that all platforms get this functionality
400 Revision 1.151 2004/02/03 22:35:34 cheshire
401 <rdar://problem/3548256>: Should not allow empty string for resolve domain
403 Revision 1.150 2004/01/28 21:14:23 cheshire
404 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
406 Revision 1.149 2004/01/28 02:30:08 ksekar
407 Added default Search Domains to unicast browsing, controlled via
408 Networking sharing prefs pane. Stopped sending unicast messages on
409 every interface. Fixed unicast resolving via mach-port API.
411 Revision 1.148 2004/01/25 00:03:20 cheshire
412 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
414 Revision 1.147 2004/01/19 19:51:46 cheshire
415 Fix compiler error (mixed declarations and code) on some versions of Linux
417 Revision 1.146 2003/12/08 21:00:46 rpantos
418 Changes to support mDNSResponder on Linux.
420 Revision 1.145 2003/12/05 22:08:07 cheshire
421 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
423 Revision 1.144 2003/11/19 23:21:08 ksekar
424 <rdar://problem/3486646>: config change handler not called for dns-sd services
426 Revision 1.143 2003/11/14 21:18:32 cheshire
427 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
428 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
430 Revision 1.142 2003/11/08 22:18:29 cheshire
431 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
433 Revision 1.141 2003/11/07 02:30:57 cheshire
434 Also check per-slot cache use counts in SIGINFO state log
436 Revision 1.140 2003/10/21 19:58:26 cheshire
437 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
439 Revision 1.139 2003/10/21 00:10:18 rpantos
440 <rdar://problem/3409401>: mDNSResponder should not run as root
442 Revision 1.138 2003/10/07 20:16:58 cheshire
443 Shorten syslog message a bit
445 Revision 1.137 2003/09/23 02:12:43 cheshire
446 Also include port number in list of services registered via new UDS API
448 Revision 1.136 2003/09/23 02:07:25 cheshire
449 Include port number in DNSServiceRegistration START/STOP messages
451 Revision 1.135 2003/09/23 01:34:02 cheshire
452 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
454 Revision 1.134 2003/08/21 20:01:37 cheshire
455 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
457 Revision 1.133 2003/08/20 23:39:31 cheshire
458 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
460 Revision 1.132 2003/08/20 01:44:56 cheshire
461 Fix errors in LogOperation() calls (only used for debugging)
463 Revision 1.131 2003/08/19 05:39:43 cheshire
464 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
466 Revision 1.130 2003/08/16 03:39:01 cheshire
467 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
469 Revision 1.129 2003/08/15 20:16:03 cheshire
470 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
471 We want to avoid touching the rdata pages, so we don't page them in.
472 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
473 Moved this from the RData to the ResourceRecord object.
474 2. To avoid unnecessarily touching the rdata just to compare it,
475 compute a hash of the rdata and store the hash in the ResourceRecord object.
477 Revision 1.128 2003/08/14 19:30:36 cheshire
478 <rdar://problem/3378473> Include list of cache records in SIGINFO output
480 Revision 1.127 2003/08/14 02:18:21 cheshire
481 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
483 Revision 1.126 2003/08/12 19:56:25 cheshire
486 Revision 1.125 2003/08/08 18:36:04 cheshire
487 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
489 Revision 1.124 2003/07/25 18:28:23 cheshire
490 Minor fix to error messages in syslog: Display string parameters with quotes
492 Revision 1.123 2003/07/23 17:45:28 cheshire
493 <rdar://problem/3339388> mDNSResponder leaks a bit
494 Don't allocate memory for the reply until after we've verified that the reply is valid
496 Revision 1.122 2003/07/23 00:00:04 cheshire
499 Revision 1.121 2003/07/20 03:38:51 ksekar
500 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
502 Revision 1.120 2003/07/18 00:30:00 cheshire
503 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
505 Revision 1.119 2003/07/17 19:08:58 cheshire
506 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
508 Revision 1.118 2003/07/15 21:12:28 cheshire
509 Added extra debugging checks in validatelists() (not used in final shipping version)
511 Revision 1.117 2003/07/15 01:55:15 cheshire
512 <rdar://problem/3315777> Need to implement service registration with subtypes
514 Revision 1.116 2003/07/02 21:19:51 cheshire
515 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
517 Revision 1.115 2003/07/02 02:41:24 cheshire
518 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
520 Revision 1.114 2003/07/01 21:10:20 cheshire
521 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
523 Revision 1.113 2003/06/28 17:27:43 vlubet
524 <rdar://problem/3221246> Redirect standard input, standard output, and
525 standard error file descriptors to /dev/null just like any other
528 Revision 1.112 2003/06/25 23:42:19 ksekar
529 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
530 Reviewed by: Stuart Cheshire
531 Added files necessary to implement Unix domain sockets based enhanced
532 DNS-SD APIs, and integrated with existing Mach-port based daemon.
534 Revision 1.111 2003/06/11 01:02:43 cheshire
535 <rdar://problem/3287858> mDNSResponder binary compatibility
536 Make single binary that can run on both Jaguar and Panther.
538 Revision 1.110 2003/06/10 01:14:11 cheshire
539 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
541 Revision 1.109 2003/06/06 19:53:43 cheshire
542 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
543 (Global search-and-replace; no functional change to code execution.)
545 Revision 1.108 2003/06/06 14:08:06 cheshire
546 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
548 Revision 1.107 2003/05/29 05:44:55 cheshire
549 Minor fixes to log messages
551 Revision 1.106 2003/05/27 18:30:55 cheshire
552 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
553 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
555 Revision 1.105 2003/05/26 03:21:29 cheshire
556 Tidy up address structure naming:
557 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
558 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
559 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
561 Revision 1.104 2003/05/26 00:42:06 cheshire
562 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
564 Revision 1.103 2003/05/23 23:07:44 cheshire
565 <rdar://problem/3268199> Must not write to stderr when running as daemon
567 Revision 1.102 2003/05/22 01:32:31 cheshire
568 Fix typo in Log message format string
570 Revision 1.101 2003/05/22 00:26:55 cheshire
571 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
572 Modify error message to explain that this is technically legal, but may indicate a bug.
574 Revision 1.100 2003/05/21 21:02:24 ksekar
575 <rdar://problem/3247035>: Service should be prefixed
576 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
577 Mach message port to "com.apple.mDNSResponder.
579 Revision 1.99 2003/05/21 17:33:49 cheshire
580 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
582 Revision 1.98 2003/05/20 00:33:07 cheshire
583 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
584 SIGHUP now writes state summary to syslog
586 Revision 1.97 2003/05/08 00:19:08 cheshire
587 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
589 Revision 1.96 2003/05/07 22:10:46 cheshire
590 <rdar://problem/3250330> Add a few more error logging messages
592 Revision 1.95 2003/05/07 19:20:17 cheshire
593 <rdar://problem/3251391> Add version number to mDNSResponder builds
595 Revision 1.94 2003/05/07 00:28:18 cheshire
596 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
598 Revision 1.93 2003/05/06 00:00:49 cheshire
599 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
601 Revision 1.92 2003/04/04 20:38:57 cheshire
606 #include <mach/mach.h>
607 #include <mach/mach_error.h>
608 #include <servers/bootstrap.h>
609 #include <sys/types.h>
614 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
616 #include "DNSServiceDiscoveryRequestServer.h"
617 #include "DNSServiceDiscoveryReply.h"
619 #include "DNSCommon.h"
620 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
622 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
624 #include "GenLinkedList.h"
626 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
628 //*************************************************************************************************************
631 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
632 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
633 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
634 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
635 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
637 //*************************************************************************************************************
640 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
641 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
642 static mDNS_PlatformSupport PlatformStorage
;
644 // Start off with a default cache of 16K (about 100 records)
645 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
646 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
648 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
649 static mach_port_t client_death_port
= MACH_PORT_NULL
;
650 static mach_port_t signal_port
= MACH_PORT_NULL
;
651 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
653 // mDNS Mach Message Timeout, in milliseconds.
654 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
655 // fails to service its mach message queue, but long enough to give a well-written
656 // client a chance to service its mach message queue without getting cut off.
657 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
658 // even extra-slow clients a fair chance before we cut them off.
659 #define MDNS_MM_TIMEOUT 250
661 static int restarting_via_mach_init
= 0;
662 static int started_via_launchdaemon
= 0;
666 //*************************************************************************************************************
667 // Active client list structures
669 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
670 struct DNSServiceDomainEnumeration_struct
672 DNSServiceDomainEnumeration
*next
;
673 mach_port_t ClientMachPort
;
674 DNSQuestion dom
; // Question asking for domains
675 DNSQuestion def
; // Question asking for default domain
678 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
679 struct DNSServiceBrowserResult_struct
681 DNSServiceBrowserResult
*next
;
686 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
688 typedef struct DNSServiceBrowserQuestion
690 struct DNSServiceBrowserQuestion
*next
;
693 } DNSServiceBrowserQuestion
;
695 struct DNSServiceBrowser_struct
697 DNSServiceBrowser
*next
;
698 mach_port_t ClientMachPort
;
699 DNSServiceBrowserQuestion
*qlist
;
700 DNSServiceBrowserResult
*results
;
702 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
703 domainname type
; // registration type
706 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
707 struct DNSServiceResolver_struct
709 DNSServiceResolver
*next
;
710 mach_port_t ClientMachPort
;
716 // A single registered service: ServiceRecordSet + bookkeeping
717 // Note that we duplicate some fields from parent DNSServiceRegistration object
718 // to facilitate cleanup, when instances and parent may be deallocated at different times.
719 typedef struct ServiceInstance
721 struct ServiceInstance
*next
;
722 mach_port_t ClientMachPort
;
723 mDNSBool autoname
; // Set if this name is tied to the Computer Name
724 mDNSBool autorename
; // Set if we just got a name conflict and now need to automatically pick a new name
727 ServiceRecordSet srs
;
728 // Don't add any fields after ServiceRecordSet.
729 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
732 // A client-created service. May reference several ServiceInstance objects if default
733 // settings cause registration in multiple domains.
734 typedef struct DNSServiceRegistration
736 struct DNSServiceRegistration
*next
;
737 mach_port_t ClientMachPort
;
738 mDNSBool DefaultDomain
;
742 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
743 domainlabel name
; // used only if autoname is false
746 unsigned char txtinfo
[1024];
749 ServiceInstance
*regs
;
750 } DNSServiceRegistration
;
752 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
753 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
754 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
755 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
757 //*************************************************************************************************************
758 // General Utility Functions
760 #if MACOSX_MDNS_MALLOC_DEBUGGING
762 char _malloc_options
[] = "AXZ";
764 mDNSexport
void LogMemCorruption(const char *format
, ...)
768 va_start(ptr
,format
);
769 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
771 LogMsg("!!!! %s !!!!", buffer
);
772 NotifyOfElusiveBug("Memory Corruption", 0, buffer
);
775 mDNSlocal
void validatelists(mDNS
*const m
)
777 // Check Mach client lists
779 DNSServiceDomainEnumeration
*e
;
780 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
781 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
782 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e
, e
->ClientMachPort
);
784 DNSServiceBrowser
*b
;
785 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
786 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
787 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b
, b
->ClientMachPort
);
789 DNSServiceResolver
*l
;
790 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
791 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
792 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l
, l
->ClientMachPort
);
794 DNSServiceRegistration
*r
;
795 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
796 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
797 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r
, r
->ClientMachPort
);
799 // Check UDS client lists
802 // Check core mDNS lists
804 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
806 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
807 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
808 if (rr
->resrec
.name
!= &rr
->namestorage
)
809 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
810 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
813 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
814 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
815 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
818 for (q
= m
->Questions
; q
; q
=q
->next
)
819 if (q
->ThisQInterval
== (mDNSs32
)~0)
820 LogMemCorruption("Questions list: %p is garbage (%lX)", q
, q
->ThisQInterval
);
825 FORALL_CACHERECORDS(slot
, cg
, cr
)
826 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
827 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot
, rr
, rr
->resrec
.RecordType
);
829 // Check platform-layer lists
831 NetworkInterfaceInfoOSX
*i
;
832 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
834 LogMemCorruption("InterfaceList: %p is garbage", i
);
838 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
=q
->next
)
839 if (*(long*)q
== (mDNSs32
)~0)
840 LogMemCorruption("uDNS_info.ActiveQueries: %p is garbage (%lX)", q
, *(long*)q
);
843 for (s
= m
->uDNS_info
.ServiceRegistrations
; s
; s
=s
->next
)
844 if (s
->next
== (ServiceRecordSet
*)~0)
845 LogMemCorruption("uDNS_info.ServiceRegistrations: %p is garbage (%lX)", s
, s
->next
);
847 for (rr
= m
->uDNS_info
.RecordRegistrations
; rr
; rr
=rr
->next
)
849 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
850 LogMemCorruption("uDNS_info.RecordRegistrations: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
851 if (rr
->resrec
.name
!= &rr
->namestorage
)
852 LogMemCorruption("uDNS_info.RecordRegistrations: %p name %p does not point to namestorage %p %##s",
853 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
857 for (n
= m
->uDNS_info
.NATTraversals
; n
; n
=n
->next
)
858 if (n
->op
> 2) LogMemCorruption("uDNS_info.NATTraversals: %p is garbage", n
);
860 for (n
= m
->uDNS_info
.LLQNatInfo
; n
; n
=n
->next
)
861 if (n
->op
> 2) LogMemCorruption("uDNS_info.LLQNatInfo: %p is garbage", n
);
864 void *mallocL(char *msg
, unsigned int size
)
866 unsigned long *mem
= malloc(size
+8);
869 LogMsg("malloc( %s : %d ) failed", msg
, size
);
874 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
877 //bzero(&mem[2], size);
878 memset(&mem
[2], 0xFF, size
);
879 validatelists(&mDNSStorage
);
884 void freeL(char *msg
, void *x
)
887 LogMsg("free( %s @ NULL )!", msg
);
890 unsigned long *mem
= ((unsigned long *)x
) - 2;
891 if (mem
[0] != 0xDEAD1234)
892 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
894 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
895 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
896 //bzero(mem, mem[1]+8);
897 memset(mem
, 0xFF, mem
[1]+8);
898 validatelists(&mDNSStorage
);
905 //*************************************************************************************************************
906 // Client Death Detection
908 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
910 ServiceRecordSet
*s
= &x
->srs
;
911 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
915 e
->r
.RecordContext
= e
;
918 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
921 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
922 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
924 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
925 freeL("ServiceInstance", x
);
928 // AbortClient finds whatever client is identified by the given Mach port,
929 // stops whatever operation that client was doing, and frees its memory.
930 // In the case of a service registration, the actual freeing may be deferred
931 // until we get the mStatus_MemFree message, if necessary
932 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
934 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
935 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
936 DNSServiceResolver
**l
= &DNSServiceResolverList
;
937 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
939 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
942 DNSServiceDomainEnumeration
*x
= *e
;
945 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
946 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
947 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
948 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
949 freeL("DNSServiceDomainEnumeration", x
);
953 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
956 DNSServiceBrowser
*x
= *b
;
957 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
962 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
963 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
964 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
967 freeL("DNSServiceBrowserQuestion", freePtr
);
971 DNSServiceBrowserResult
*r
= x
->results
;
972 x
->results
= x
->results
->next
;
973 freeL("DNSServiceBrowserResult", r
);
975 freeL("DNSServiceBrowser", x
);
979 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
982 DNSServiceResolver
*x
= *l
;
985 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
986 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
987 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
988 freeL("DNSServiceResolver", x
);
992 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
995 ServiceInstance
*si
= NULL
;
996 DNSServiceRegistration
*x
= *r
;
1002 ServiceInstance
*instance
= si
;
1004 instance
->autorename
= mDNSfalse
;
1005 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
);
1006 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
1008 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
1009 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
1010 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
1011 // the list, so we should go ahead and free the memory right now
1012 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
1015 freeL("DNSServiceRegistration", x
);
1019 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
1022 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
1024 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
1026 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1027 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1028 DNSServiceResolver
*l
= DNSServiceResolverList
;
1029 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1030 DNSServiceBrowserQuestion
*qptr
;
1032 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1033 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1034 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1035 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1037 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
1040 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1041 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
1043 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
1046 ServiceInstance
*si
;
1047 for (si
= r
->regs
; si
; si
= si
->next
)
1048 LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
1050 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
1055 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
1057 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1058 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1059 DNSServiceResolver
*l
= DNSServiceResolverList
;
1060 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1061 DNSServiceBrowserQuestion
*qptr
;
1063 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1064 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1065 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1066 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1067 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
1070 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1071 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
1073 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
1074 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
1075 return(e
|| b
|| l
|| r
);
1078 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
1080 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
1081 (void)unusedport
; // Unused
1082 (void)size
; // Unused
1083 (void)info
; // Unused
1084 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1086 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
1087 AbortClient(deathMessage
->not_port
, NULL
);
1089 /* Deallocate the send right that came in the dead name notification */
1090 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
1094 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
1097 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
1098 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
1099 // If the port already died while we were thinking about it, then abort the operation right away
1100 if (r
!= KERN_SUCCESS
)
1101 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1104 //*************************************************************************************************************
1105 // Domain Enumeration
1107 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1109 kern_return_t status
;
1111 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1112 DNSServiceDomainEnumerationReplyResultType rt
;
1113 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1115 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1116 if (answer
->rrtype
!= kDNSType_PTR
) return;
1117 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1121 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1122 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1126 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1130 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1131 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1132 !AddRecord
? "RemoveDomain" :
1133 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1135 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1136 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1137 if (status
== MACH_SEND_TIMED_OUT
)
1138 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1141 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1144 // Check client parameter
1145 (void)unusedserver
; // Unused
1146 mStatus err
= mStatus_NoError
;
1147 const char *errormsg
= "Unknown";
1148 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1149 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1151 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1152 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1154 // Allocate memory, and handle failure
1155 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1156 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1158 // Set up object, and link into list
1159 x
->ClientMachPort
= client
;
1160 x
->next
= DNSServiceDomainEnumerationList
;
1161 DNSServiceDomainEnumerationList
= x
;
1163 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1166 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1167 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1168 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1170 // Succeeded: Wrap up and return
1171 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1172 EnableDeathNotificationForClient(client
, x
);
1173 return(mStatus_NoError
);
1176 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
1180 //*************************************************************************************************************
1181 // Browse for services
1183 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1187 if (answer
->rrtype
!= kDNSType_PTR
)
1188 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1191 domainname type
, domain
;
1192 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1194 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1195 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1199 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1200 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1202 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1203 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1205 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1206 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1209 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1210 DNSServiceBrowserResult
**p
= &browser
->results
;
1211 while (*p
) p
= &(*p
)->next
;
1215 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1217 mStatus err
= mStatus_NoError
;
1218 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1220 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1222 if (SameDomainName(&ptr
->q
.qname
, d
))
1223 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1226 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1227 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1228 AssignDomainName(&question
->domain
, d
);
1229 question
->next
= browser
->qlist
;
1230 browser
->qlist
= question
;
1231 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1232 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1233 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1237 mDNSexport
void DefaultBrowseDomainChanged(const domainname
*d
, mDNSBool add
)
1239 DNSServiceBrowser
*ptr
;
1241 debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
1242 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1244 if (ptr
->DefaultDomain
)
1248 mStatus err
= AddDomainToBrowser(ptr
, d
);
1249 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1253 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1256 if (SameDomainName(&(*q
)->domain
, d
))
1258 DNSServiceBrowserQuestion
*remove
= *q
;
1260 if (remove
->q
.LongLived
)
1262 // give goodbyes for known answers. note that since events are sent to client via udns_execute(),
1263 // we don't need to worry about the question being cancelled mid-loop
1264 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
1265 while (ka
) { remove
->q
.QuestionCallback(&mDNSStorage
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
1267 mDNS_StopBrowse(&mDNSStorage
, &remove
->q
);
1268 freeL("DNSServiceBrowserQuestion", remove
);
1273 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1279 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1280 DNSCString regtype
, DNSCString domain
)
1282 // Check client parameter
1283 (void)unusedserver
; // Unused
1284 mStatus err
= mStatus_NoError
;
1285 const char *errormsg
= "Unknown";
1286 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
1288 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1289 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1291 // Check other parameters
1294 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1295 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1296 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1297 { errormsg
= "Bad Service SubType"; goto badparam
; }
1298 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1300 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1301 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1303 // Allocate memory, and handle failure
1304 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1305 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1307 // Set up object, and link into list
1308 AssignDomainName(&x
->type
, &t
);
1309 x
->ClientMachPort
= client
;
1313 x
->next
= DNSServiceBrowserList
;
1314 DNSServiceBrowserList
= x
;
1318 // Start browser for an explicit domain
1319 x
->DefaultDomain
= mDNSfalse
;
1320 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1321 err
= AddDomainToBrowser(x
, &d
);
1322 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1326 // Start browser on all domains
1327 x
->DefaultDomain
= mDNStrue
;
1328 SearchDomains
= mDNSPlatformGetSearchDomainList();
1329 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1330 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1332 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1335 // only terminally bail if .local fails
1336 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1337 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1338 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1343 // Succeeded: Wrap up and return
1344 EnableDeathNotificationForClient(client
, x
);
1345 mDNS_FreeDNameList(SearchDomains
);
1346 return(mStatus_NoError
);
1349 err
= mStatus_BadParamErr
;
1351 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1352 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
1356 //*************************************************************************************************************
1357 // Resolve Service Info
1359 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1361 kern_return_t status
;
1362 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1363 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1364 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1365 struct sockaddr_storage interface
;
1366 struct sockaddr_storage address
;
1368 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1371 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1373 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1375 bzero(&interface
, sizeof(interface
));
1376 bzero(&address
, sizeof(address
));
1378 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1380 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1381 sin
->sin_len
= sizeof(*sin
);
1382 sin
->sin_family
= AF_INET
;
1384 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1386 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1388 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1389 sin6
->sin6_len
= sizeof(*sin6
);
1390 sin6
->sin6_family
= AF_INET6
;
1391 sin6
->sin6_flowinfo
= 0;
1392 sin6
->sin6_port
= 0;
1393 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1394 sin6
->sin6_scope_id
= ifx
->scope_id
;
1397 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1399 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1400 sin
->sin_len
= sizeof(*sin
);
1401 sin
->sin_family
= AF_INET
;
1402 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1403 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1407 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1408 sin6
->sin6_len
= sizeof(*sin6
);
1409 sin6
->sin6_family
= AF_INET6
;
1410 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1411 sin6
->sin6_flowinfo
= 0;
1412 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1413 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1416 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1417 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1418 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1419 // ASCII-1 characters are used in the C-string as boundary markers,
1420 // to indicate the boundaries between the original constituent P-strings.
1421 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1424 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1428 pstrlen
= query
->info
->TXTinfo
[i
];
1431 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1433 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1434 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1435 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1436 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1437 if (status
== MACH_SEND_TIMED_OUT
)
1438 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1441 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1442 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1444 // Check client parameter
1445 (void)unusedserver
; // Unused
1446 mStatus err
= mStatus_NoError
;
1447 const char *errormsg
= "Unknown";
1448 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1449 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1451 // Check other parameters
1453 domainname t
, d
, srv
;
1454 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1455 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1456 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1457 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1459 // Allocate memory, and handle failure
1460 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1461 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1463 // Set up object, and link into list
1464 x
->ClientMachPort
= client
;
1465 x
->i
.InterfaceID
= mDNSInterface_Any
;
1467 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1468 x
->next
= DNSServiceResolverList
;
1469 DNSServiceResolverList
= x
;
1472 LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
);
1473 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1474 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1476 // Succeeded: Wrap up and return
1477 EnableDeathNotificationForClient(client
, x
);
1478 return(mStatus_NoError
);
1481 err
= mStatus_BadParamErr
;
1483 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1487 //*************************************************************************************************************
1490 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1492 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1495 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1497 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1499 if (result
== mStatus_NoError
)
1501 kern_return_t status
;
1502 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1503 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1504 if (status
== MACH_SEND_TIMED_OUT
)
1505 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1506 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1507 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1510 else if (result
== mStatus_NameConflict
)
1512 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1513 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1514 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1515 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1517 // On conflict for an autoname service, rename and reregister *all* autoname services
1518 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1519 m
->MainCallback(m
, mStatus_ConfigChanged
);
1521 else if (si
->autoname
)
1523 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1528 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1529 // of their registration in the usual way (which we will catch via client death notification).
1530 // If the Mach queue is full, we forcibly abort the client immediately.
1531 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1532 if (status
== MACH_SEND_TIMED_OUT
)
1533 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1537 else if (result
== mStatus_MemFree
)
1541 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1542 si
->autorename
= mDNSfalse
;
1543 si
->name
= m
->nicelabel
;
1544 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1548 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1549 DNSServiceRegistration
*r
;
1550 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1552 ServiceInstance
*sp
= r
->regs
, *prev
= NULL
;
1557 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
->c
);
1558 if (prev
) prev
->next
= sp
->next
;
1559 else r
->regs
= sp
->next
;
1567 FreeServiceInstance(si
);
1571 else if (result
!= mStatus_NATTraversal
)
1572 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1575 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1578 ServiceInstance
*si
= NULL
;
1579 AuthRecord
*SubTypes
= NULL
;
1581 for (si
= x
->regs
; si
; si
= si
->next
)
1583 if (SameDomainName(&si
->domain
, domain
))
1584 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1587 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1588 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1590 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1591 if (!si
) return mStatus_NoMemoryErr
;
1593 si
->ClientMachPort
= x
->ClientMachPort
;
1594 si
->autorename
= mDNSfalse
;
1595 si
->autoname
= x
->autoname
;
1596 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1597 si
->domain
= *domain
;
1599 err
= mDNS_RegisterService(&mDNSStorage
, &si
->srs
, &si
->name
, &x
->type
, domain
, NULL
, x
->port
, x
->txtinfo
, x
->txt_len
, SubTypes
, x
->NumSubTypes
, mDNSInterface_Any
, RegCallback
, si
);
1607 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1608 freeL("ServiceInstance", si
);
1613 mDNSexport
void DefaultRegDomainChanged(const domainname
*d
, mDNSBool add
)
1615 DNSServiceRegistration
*reg
;
1617 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1619 if (reg
->DefaultDomain
)
1623 AddServiceInstance(reg
, d
);
1627 ServiceInstance
*si
= reg
->regs
, *prev
= NULL
;
1630 if (SameDomainName(&si
->domain
, d
))
1632 if (prev
) prev
->next
= si
->next
;
1633 else reg
->regs
= si
->next
;
1634 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
))
1635 FreeServiceInstance(si
); // only free memory synchronously on error
1641 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1647 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1648 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1650 (void)unusedserver
; // Unused
1651 mStatus err
= mStatus_NoError
;
1652 const char *errormsg
= "Unknown";
1654 // older versions of this code passed the port via mach IPC as an int.
1655 // we continue to pass it as 4 bytes to maintain binary compatibility,
1656 // but now ensure that the network byte order is preserved by using a struct
1658 port
.b
[0] = IpPort
.bytes
[2];
1659 port
.b
[1] = IpPort
.bytes
[3];
1661 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1662 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1664 // Check for sub-types after the service type
1665 size_t reglen
= strlen(regtype
) + 1;
1666 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1667 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1668 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1670 // Check other parameters
1674 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1675 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1676 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1677 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1678 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1680 unsigned char txtinfo
[1024] = "";
1681 unsigned int data_len
= 0;
1682 unsigned int size
= sizeof(RDataBody
);
1683 unsigned char *pstring
= &txtinfo
[data_len
];
1684 char *ptr
= txtRecord
;
1686 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1687 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1688 // Hence we have to convert the C-string to a P-string.
1689 // ASCII-1 characters are allowed in the C-string as boundary markers,
1690 // so that a single C-string can be used to represent one or more P-strings.
1693 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1694 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1696 pstring
= &txtinfo
[data_len
];
1702 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1703 pstring
[++pstring
[0]] = *ptr
++;
1708 if (size
< data_len
)
1711 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1712 // a port number of zero. When two instances of the protected client are allowed to run on one
1713 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1714 if (port
.NotAnInteger
)
1716 int count
= CountExistingRegistrations(&srv
, port
);
1718 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1719 client
, count
+1, srv
.c
, mDNSVal16(port
));
1722 // Allocate memory, and handle failure
1723 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1724 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1725 bzero(x
, sizeof(*x
));
1727 // Set up object, and link into list
1728 x
->ClientMachPort
= client
;
1729 x
->DefaultDomain
= !domain
[0];
1730 x
->autoname
= (!name
[0]);
1732 x
->NumSubTypes
= NumSubTypes
;
1733 memcpy(x
->regtype
, regtype
, reglen
);
1737 memcpy(x
->txtinfo
, txtinfo
, 1024);
1738 x
->txt_len
= data_len
;
1742 x
->next
= DNSServiceRegistrationList
;
1743 DNSServiceRegistrationList
= x
;
1745 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1746 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1748 err
= AddServiceInstance(x
, &d
);
1749 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1751 if (x
->DefaultDomain
)
1753 DNameListElem
*ptr
, *regdomains
= mDNSPlatformGetRegDomainList();
1754 for (ptr
= regdomains
; ptr
; ptr
= ptr
->next
)
1755 AddServiceInstance(x
, &ptr
->name
);
1756 mDNS_FreeDNameList(regdomains
);
1759 // Succeeded: Wrap up and return
1760 EnableDeathNotificationForClient(client
, x
);
1761 return(mStatus_NoError
);
1764 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1766 err
= mStatus_BadParamErr
;
1768 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1769 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1773 mDNSlocal CFUserNotificationRef gNotification
= NULL
;
1774 mDNSlocal CFRunLoopSourceRef gNotificationRLS
= NULL
;
1775 mDNSlocal domainlabel gNotificationPrefHostLabel
; // The prefs as they were the last time we saw them
1776 mDNSlocal domainlabel gNotificationPrefNiceLabel
;
1777 mDNSlocal domainlabel gNotificationUserHostLabel
; // The prefs as they were the last time the user changed them
1778 mDNSlocal domainlabel gNotificationUserNiceLabel
;
1780 mDNSlocal
void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
1782 (void)responseFlags
; // Unused
1783 if (userNotification
!= gNotification
) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
1784 if (gNotificationRLS
)
1786 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1787 CFRelease(gNotificationRLS
);
1788 gNotificationRLS
= NULL
;
1789 CFRelease(gNotification
);
1790 gNotification
= NULL
;
1792 // By dismissing the alert, the user has conceptually acknowleged the rename.
1793 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
1794 // If we get *another* conflict, the new alert should refer to the 'old'.
1795 // name as now being "computer-2.local", not "computer.local"
1796 gNotificationUserHostLabel
= gNotificationPrefHostLabel
;
1797 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
;
1800 mDNSlocal
void ShowNameConflictNotification(CFStringRef header
, CFStringRef subtext
)
1802 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1803 if (!dictionary
) return;
1804 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
1805 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
1807 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
1808 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
1810 if (gNotification
) // If notification already on-screen, update it in place
1811 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
1812 else // else, we need to create it
1815 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
1816 if (!gNotification
) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
1817 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
1818 if (!gNotificationRLS
) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
1819 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1822 CFRelease(dictionary
);
1825 // This updates either the text of the field currently labelled "Local Hostname",
1826 // or the text of the field currently labelled "Computer Name"
1827 // in the Sharing Prefs Control Panel
1828 mDNSlocal
void RecordUpdatedName(const mDNS
*const m
, const domainlabel
*const olddl
, const domainlabel
*const newdl
,
1829 const char *const msg
, const char *const suffix
, const CFStringRef subtext
)
1831 char oldname
[MAX_DOMAIN_LABEL
+1];
1832 char newname
[MAX_DOMAIN_LABEL
+1];
1833 ConvertDomainLabelToCString_unescaped(olddl
, oldname
);
1834 ConvertDomainLabelToCString_unescaped(newdl
, newname
);
1835 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
1836 const CFStringRef cfnewname
= CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
);
1837 const CFStringRef f1
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1838 const CFStringRef f2
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1839 const SCPreferencesRef session
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
);
1840 if (!cfoldname
|| !cfnewname
|| !f1
|| !f2
|| !session
|| !SCPreferencesLock(session
, 0)) // If we can't get the lock don't wait
1841 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1844 const CFStringRef s0
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1845 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
);
1846 const CFStringRef s2
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
);
1847 // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
1848 // element of the array individually for us, and then concatenate the results to make the final message.
1849 // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
1850 // On Panther this does not work, so we just build the string directly, and it will not be translated.
1851 const CFMutableStringRef alertHeader
=
1852 (OSXVers
< 8) ? CFStringCreateMutable(NULL
, 0) : (CFMutableStringRef
)CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1854 if (newdl
== &gNotificationPrefHostLabel
) result
= SCPreferencesSetLocalHostName(session
, cfnewname
);
1855 else result
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
);
1856 if (!result
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0
|| !s1
|| !s2
|| !alertHeader
)
1857 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1858 else if (m
->p
->NotifyUser
)
1862 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
1865 CFRelease(userName
);
1866 typedef void CFStringAppendFN(CFMutableStringRef theString
, CFStringRef appendedString
);
1867 CFStringAppendFN
*const append
= (OSXVers
< 8) ? &CFStringAppend
: (CFStringAppendFN
*)&CFArrayAppendValue
;
1868 append(alertHeader
, s0
);
1869 append(alertHeader
, s1
);
1870 append(alertHeader
, CFSTR("is already in use on this network."));
1871 append(alertHeader
, CFSTR(" "));
1872 append(alertHeader
, CFSTR("The name has been changed to"));
1873 append(alertHeader
, s2
);
1874 append(alertHeader
, CFSTR("automatically."));
1875 ShowNameConflictNotification(alertHeader
, subtext
);
1878 if (s0
) CFRelease(s0
);
1879 if (s1
) CFRelease(s1
);
1880 if (s2
) CFRelease(s2
);
1881 if (alertHeader
) CFRelease(alertHeader
);
1882 SCPreferencesUnlock(session
);
1884 if (cfoldname
) CFRelease(cfoldname
);
1885 if (cfnewname
) CFRelease(cfnewname
);
1886 if (f1
) CFRelease(f1
);
1887 if (f2
) CFRelease(f2
);
1888 if (session
) CFRelease(session
);
1891 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1894 if (result
== mStatus_NoError
)
1896 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1897 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1899 else if (result
== mStatus_ConfigChanged
)
1901 // If the user-specified hostlabel from System Configuration has changed since the last time
1902 // we saw it, and *we* didn't change it, then that implies that the user has changed it,
1903 // so we auto-dismiss the name conflict alert.
1904 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, gNotificationPrefHostLabel
.c
) ||
1905 !SameDomainLabel(m
->p
->usernicelabel
.c
, gNotificationPrefNiceLabel
.c
))
1907 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= m
->p
->userhostlabel
;
1908 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= m
->p
->usernicelabel
;
1909 // If we're showing a name conflict notification, and the user has manually edited
1910 // the name to remedy the conflict, we should now remove the notification window.
1911 if (gNotificationRLS
) CFUserNotificationCancel(gNotification
);
1914 DNSServiceRegistration
*r
;
1915 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1918 ServiceInstance
*si
;
1919 for (si
= r
->regs
; si
; si
= si
->next
)
1921 if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
))
1923 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1924 si
->autorename
= mDNStrue
;
1925 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1926 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1930 udsserver_handle_configchange();
1932 else if (result
== mStatus_GrowCache
)
1934 // Allocate another chunk of cache storage
1935 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1936 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1940 //*************************************************************************************************************
1941 // Add / Update / Remove records from existing Registration
1943 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1944 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1946 // Check client parameter
1948 mStatus err
= mStatus_NoError
;
1949 const char *errormsg
= "Unknown";
1950 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1951 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1952 ServiceInstance
*si
;
1954 (void)unusedserver
; // Unused
1955 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1956 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1958 // Check other parameters
1959 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1960 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1961 else size
= sizeof(RDataBody
);
1964 *reference
= (natural_t
)id
;
1965 for (si
= x
->regs
; si
; si
= si
->next
)
1967 // Allocate memory, and handle failure
1968 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1969 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1971 // Fill in type, length, and data of new record
1972 extra
->r
.resrec
.rrtype
= type
;
1973 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1974 extra
->r
.resrec
.rdlength
= data_len
;
1975 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1978 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1979 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1980 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1984 freeL("Extra Resource Record", extra
);
1985 errormsg
= "mDNS_AddRecordToService";
1989 extra
->ClientID
= id
;
1992 return mStatus_NoError
;
1995 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
1996 return mStatus_UnknownErr
;
1999 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
2002 if (OldRData
!= &rr
->rdatastorage
)
2003 freeL("Old RData", OldRData
);
2006 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
2008 // Check client parameter
2009 mStatus err
= mStatus_NoError
;
2010 const char *errormsg
= "Unknown";
2011 domainname
*name
= (domainname
*)"";
2013 name
= srs
->RR_SRV
.resrec
.name
;
2015 unsigned int size
= sizeof(RDataBody
);
2016 if (size
< data_len
)
2019 // Allocate memory, and handle failure
2020 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
2021 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
2023 // Fill in new length, and data
2024 newrdata
->MaxRDLength
= size
;
2025 memcpy(&newrdata
->u
, data
, data_len
);
2027 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2028 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2029 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2030 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
2033 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
2034 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
2036 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
2039 errormsg
= "mDNS_Update";
2040 freeL("RData", newrdata
);
2043 return(mStatus_NoError
);
2046 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
2050 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2051 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
2053 // Check client parameter
2054 mStatus err
= mStatus_NoError
;
2055 const char *errormsg
= "Unknown";
2056 domainname
*name
= (domainname
*)"";
2057 ServiceInstance
*si
;
2059 (void)unusedserver
; // unused
2060 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2061 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2062 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2063 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2065 // Check other parameters
2066 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
2068 for (si
= x
->regs
; si
; si
= si
->next
)
2070 AuthRecord
*r
= NULL
;
2072 // Find the record we're updating. NULL reference means update the primary TXT record
2073 if (!reference
) r
= &si
->srs
.RR_TXT
;
2076 ExtraResourceRecord
*ptr
;
2077 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2079 if ((natural_t
)ptr
->ClientID
== reference
)
2080 { r
= &ptr
->r
; break; }
2082 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
2084 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
2085 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
2088 return mStatus_NoError
;
2091 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
2095 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
2097 domainname
*name
= srs
->RR_SRV
.resrec
.name
;
2098 mStatus err
= mStatus_NoError
;
2101 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
2103 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
2104 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
2109 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2110 natural_t reference
)
2112 // Check client parameter
2113 (void)unusedserver
; // Unused
2114 mStatus err
= mStatus_NoError
;
2115 const char *errormsg
= "Unknown";
2116 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2117 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2118 ServiceInstance
*si
;
2120 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2121 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2123 for (si
= x
->regs
; si
; si
= si
->next
)
2125 ExtraResourceRecord
*e
;
2126 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
2128 if ((natural_t
)e
->ClientID
== reference
)
2130 err
= RemoveRecord(&si
->srs
, e
, client
);
2134 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
2137 return mStatus_NoError
;
2140 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
2144 //*************************************************************************************************************
2147 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2149 mig_reply_error_t
*request
= msg
;
2150 mig_reply_error_t
*reply
;
2151 mach_msg_return_t mr
;
2153 (void)port
; // Unused
2154 (void)size
; // Unused
2155 (void)info
; // Unused
2157 /* allocate a reply buffer */
2158 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
2160 /* call the MiG server routine */
2161 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
2163 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
2165 if (reply
->RetCode
== MIG_NO_REPLY
)
2168 * This return code is a little tricky -- it appears that the
2169 * demux routine found an error of some sort, but since that
2170 * error would not normally get returned either to the local
2171 * user or the remote one, we pretend it's ok.
2173 CFAllocatorDeallocate(NULL
, reply
);
2178 * destroy any out-of-line data in the request buffer but don't destroy
2179 * the reply port right (since we need that to send an error message).
2181 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2182 mach_msg_destroy(&request
->Head
);
2185 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2187 /* no reply port, so destroy the reply */
2188 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2189 mach_msg_destroy(&reply
->Head
);
2190 CFAllocatorDeallocate(NULL
, reply
);
2197 * We don't want to block indefinitely because the client
2198 * isn't receiving messages from the reply port.
2199 * If we have a send-once right for the reply port, then
2200 * this isn't a concern because the send won't block.
2201 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2202 * To avoid falling off the kernel's fast RPC path unnecessarily,
2203 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2206 options
= MACH_SEND_MSG
;
2207 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2208 options
|= MACH_SEND_TIMEOUT
;
2210 mr
= mach_msg(&reply
->Head
, /* msg */
2211 options
, /* option */
2212 reply
->Head
.msgh_size
, /* send_size */
2214 MACH_PORT_NULL
, /* rcv_name */
2215 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2216 MACH_PORT_NULL
); /* notify */
2218 /* Has a message error occurred? */
2221 case MACH_SEND_INVALID_DEST
:
2222 case MACH_SEND_TIMED_OUT
:
2223 /* the reply can't be delivered, so destroy it */
2224 mach_msg_destroy(&reply
->Head
);
2228 /* Includes success case. */
2232 CFAllocatorDeallocate(NULL
, reply
);
2235 mDNSlocal kern_return_t
registerBootstrapService()
2237 kern_return_t status
;
2238 mach_port_t service_send_port
, service_rcv_port
;
2240 debugf("Registering Bootstrap Service");
2243 * See if our service name is already registered and if we have privilege to check in.
2245 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2246 if (status
== KERN_SUCCESS
)
2249 * If so, we must be a followup instance of an already defined server. In that case,
2250 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2251 * that in case we have to unregister later (which requires the privilege port).
2253 server_priv_port
= bootstrap_port
;
2254 restarting_via_mach_init
= TRUE
;
2256 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2258 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2259 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2260 if (status
!= KERN_SUCCESS
) return status
;
2262 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2263 if (status
!= KERN_SUCCESS
)
2265 mach_port_deallocate(mach_task_self(), server_priv_port
);
2269 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2270 if (status
!= KERN_SUCCESS
)
2272 mach_port_deallocate(mach_task_self(), server_priv_port
);
2273 mach_port_deallocate(mach_task_self(), service_send_port
);
2276 assert(service_send_port
== service_rcv_port
);
2280 * We have no intention of responding to requests on the service port. We are not otherwise
2281 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2282 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2283 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2285 mach_port_destroy(mach_task_self(), service_rcv_port
);
2289 mDNSlocal kern_return_t
destroyBootstrapService()
2291 debugf("Destroying Bootstrap Service");
2292 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2295 mDNSlocal
void ExitCallback(int signal
)
2297 LogMsgIdent(mDNSResponderVersionString
, "stopping");
2299 debugf("ExitCallback");
2300 if (!mDNS_DebugMode
&& !started_via_launchdaemon
&& signal
!= SIGHUP
)
2301 destroyBootstrapService();
2303 debugf("ExitCallback: Aborting MIG clients");
2304 while (DNSServiceDomainEnumerationList
)
2305 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2306 while (DNSServiceBrowserList
)
2307 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2308 while (DNSServiceResolverList
)
2309 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2310 while (DNSServiceRegistrationList
)
2311 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2313 debugf("ExitCallback: mDNS_Close");
2314 mDNS_Close(&mDNSStorage
);
2315 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2319 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2320 mDNSlocal
void HandleSIG(int signal
)
2323 debugf("HandleSIG %d", signal
);
2324 mach_msg_header_t header
;
2325 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2326 header
.msgh_remote_port
= signal_port
;
2327 header
.msgh_local_port
= MACH_PORT_NULL
;
2328 header
.msgh_size
= sizeof(header
);
2329 header
.msgh_id
= signal
;
2330 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2332 LogMsg("HandleSIG %d: mach_msg_send failed", signal
);
2333 if (signal
== SIGHUP
|| signal
== SIGTERM
|| signal
== SIGINT
) exit(-1);
2337 mDNSlocal
void INFOCallback(void)
2339 mDNSs32 utc
= mDNSPlatformUTC();
2340 DNSServiceDomainEnumeration
*e
;
2341 DNSServiceBrowser
*b
;
2342 DNSServiceResolver
*l
;
2343 DNSServiceRegistration
*r
;
2344 NetworkInterfaceInfoOSX
*i
;
2347 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2349 udsserver_info(&mDNSStorage
);
2351 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2352 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2354 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2356 DNSServiceBrowserQuestion
*qptr
;
2357 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2358 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2360 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2361 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2363 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2365 ServiceInstance
*si
;
2366 for (si
= r
->regs
; si
; si
= si
->next
)
2367 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
));
2370 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2373 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
2374 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, utc
- i
->LastSeen
);
2376 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2377 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2378 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2379 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
2380 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
2381 i
->ifinfo
.InterfaceID
,
2382 i
->ifinfo
.Advertise
? "Adv" : " ",
2383 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2387 for (s
= mDNSStorage
.uDNS_info
.Servers
; s
; s
= s
->next
)
2388 LogMsgNoIdent("DNS Server %#a %##s", &s
->addr
, s
->domain
.c
);
2390 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2393 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2395 (void)port
; // Unused
2396 (void)size
; // Unused
2397 (void)info
; // Unused
2398 mach_msg_header_t
*m
= (mach_msg_header_t
*)msg
;
2403 case SIGTERM
: ExitCallback(m
->msgh_id
); break;
2404 case SIGINFO
: INFOCallback(); break;
2405 case SIGUSR1
: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2406 mDNSMacOSXNetworkChanged(&mDNSStorage
); break;
2407 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break;
2411 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2412 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2414 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2417 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2418 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2419 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2420 mach_port_t m_port
= CFMachPortGetPort(s_port
);
2421 char *MachServerName
= OSXVers
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2422 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2423 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2424 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2425 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2430 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2432 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2436 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2437 rrcachestorage
, RR_CACHE_SIZE
,
2438 mDNS_Init_AdvertiseLocalAddresses
,
2439 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2441 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2443 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= PlatformStorage
.userhostlabel
;
2444 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= PlatformStorage
.usernicelabel
;
2446 client_death_port
= CFMachPortGetPort(d_port
);
2447 signal_port
= CFMachPortGetPort(i_port
);
2449 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
2450 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
2451 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
2455 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2459 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2461 mDNSs32 now
= mDNS_TimeNow(m
);
2463 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2465 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2466 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2467 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2468 // we then systematically lose our own looped-back packets.
2469 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2471 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2472 mDNSs32 nextevent
= mDNS_Execute(m
);
2474 if (m
->p
->NetworkChanged
)
2475 if (nextevent
- m
->p
->NetworkChanged
> 0)
2476 nextevent
= m
->p
->NetworkChanged
;
2478 // 3. Deliver any waiting browse messages to clients
2479 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2483 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2484 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2485 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2486 DNSServiceBrowser
*x
= b
;
2488 if (x
->results
) // Try to deliver the list of results
2492 DNSServiceBrowserResult
*const r
= x
->results
;
2494 domainname type
, domain
;
2495 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2496 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2497 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2498 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2499 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2500 ConvertDomainNameToCString(&type
, ctype
);
2501 ConvertDomainNameToCString(&domain
, cdom
);
2502 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2503 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2504 // If we failed to send the mach message, try again in one second
2505 if (status
== MACH_SEND_TIMED_OUT
)
2507 if (nextevent
- now
> mDNSPlatformOneSecond
)
2508 nextevent
= now
+ mDNSPlatformOneSecond
;
2513 x
->lastsuccess
= now
;
2514 x
->results
= x
->results
->next
;
2515 freeL("DNSServiceBrowserResult", r
);
2518 // If this client hasn't read a single message in the last 60 seconds, abort it
2519 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2520 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2524 DNSServiceResolver
*l
;
2525 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2526 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2529 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2530 "This places considerable burden on the network.", l
->i
.name
.c
);
2533 if (m
->p
->NotifyUser
)
2535 if (m
->p
->NotifyUser
- now
< 0)
2537 if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2539 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2540 gNotificationPrefNiceLabel
= m
->p
->usernicelabel
= m
->nicelabel
;
2541 RecordUpdatedName(m
, &gNotificationUserNiceLabel
, &gNotificationPrefNiceLabel
, "The name of your computer", "",
2542 CFSTR("To change the name of your computer, open System Preferences and click Sharing. "
2543 "Then type the name in the Computer Name field."));
2544 // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2545 m
->p
->NotifyUser
= 0;
2547 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2549 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2550 gNotificationPrefHostLabel
= m
->p
->userhostlabel
= m
->hostlabel
;
2551 RecordUpdatedName(m
, &gNotificationUserHostLabel
, &gNotificationPrefHostLabel
, "This computer’s local hostname", ".local",
2552 CFSTR("To change the local hostname, open System Preferences and click Sharing. "
2553 "Then click Edit and type the name in the Local Hostname field."));
2555 m
->p
->NotifyUser
= 0;
2558 if (nextevent
- m
->p
->NotifyUser
> 0)
2559 nextevent
= m
->p
->NotifyUser
;
2565 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2569 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2571 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2572 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2573 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2574 if (m
->NewLocalOnlyQuestions
)
2575 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2576 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2577 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2578 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2579 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2580 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2581 #ifndef UNICAST_DISABLED
2582 if (m
->timenow
- m
->uDNS_info
.nextevent
>= 0)
2583 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m
->timenow
- m
->uDNS_info
.nextevent
);
2585 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2586 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2587 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2588 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2589 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2590 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2591 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2592 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2594 mDNS_Unlock(&mDNSStorage
);
2597 mDNSexport
int main(int argc
, char **argv
)
2600 kern_return_t status
;
2602 for (i
=1; i
<argc
; i
++)
2604 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2605 if (!strcmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2608 signal(SIGHUP
, HandleSIG
); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2609 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2610 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2611 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2612 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2613 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2615 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2616 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2618 registerBootstrapService();
2619 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2620 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2621 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2624 // Avoid unnecessarily duplicating a file descriptor to itself
2625 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2626 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2627 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2628 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2632 // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
2633 // The sooner we do this, the faster the machine will boot.
2634 status
= udsserver_init();
2635 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
2637 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2638 LogMsgIdent(mDNSResponderVersionString
, "starting");
2639 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
2640 status
= mDNSDaemonInitialize();
2642 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2643 // Now that we're finished with anything privileged, switch over to running as "nobody"
2644 const struct passwd
*pw
= getpwnam("nobody");
2648 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2653 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2655 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2657 // This is the main work loop:
2658 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2659 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2660 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2661 // (4) On wakeup we first process *all* events
2662 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2663 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2665 // 1. Before going into a blocking wait call and letting our process to go sleep,
2666 // call mDNSDaemonIdle to allow any deferred work to be completed.
2667 mDNSs32 nextevent
= mDNSDaemonIdle(&mDNSStorage
);
2668 nextevent
= udsserver_idle(nextevent
);
2670 // 2. Work out how long we expect to sleep before the next scheduled task
2671 mDNSs32 ticks
= nextevent
- mDNS_TimeNow(&mDNSStorage
);
2672 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2678 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2680 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2682 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2683 // (a) our next wakeup time, or (b) an event occurs.
2684 // The 'true' parameter makes it return after handling any event that occurs
2685 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2686 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2688 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2690 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2691 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2694 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2698 LogMsg("ERROR: CFRunLoopRun Exiting.");
2699 mDNS_Close(&mDNSStorage
);
2702 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2705 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2709 // uds_daemon.c support routines /////////////////////////////////////////////
2711 // We keep a list of client-supplied event sources in PosixEventSource records
2712 struct CFSocketEventSource
2714 udsEventCallback Callback
;
2717 struct CFSocketEventSource
*Next
;
2719 CFRunLoopSourceRef RLS
;
2721 typedef struct CFSocketEventSource CFSocketEventSource
;
2723 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2725 mDNSlocal
void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
2726 // Called by CFSocket when data appears on socket
2732 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2733 source
->Callback(source
->Context
);
2736 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2737 // Arrange things so that callback is called with context when data appears on fd
2739 CFSocketEventSource
*newSource
;
2740 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2742 if (gEventSources
.LinkOffset
== 0)
2743 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2745 if (fd
>= FD_SETSIZE
|| fd
< 0)
2746 return mStatus_UnsupportedErr
;
2747 if (callback
== NULL
)
2748 return mStatus_BadParamErr
;
2750 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2751 if (NULL
== newSource
)
2752 return mStatus_NoMemoryErr
;
2754 newSource
->Callback
= callback
;
2755 newSource
->Context
= context
;
2758 cfContext
.info
= newSource
;
2759 if ( NULL
!= (newSource
->cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2760 cf_callback
, &cfContext
)) &&
2761 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0)))
2763 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2764 AddToTail(&gEventSources
, newSource
);
2770 CFSocketInvalidate(newSource
->cfs
); // Note: Also closes the underlying socket
2771 CFRelease(newSource
->cfs
);
2773 return mStatus_NoMemoryErr
;
2776 return mStatus_NoError
;
2779 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2780 // Reverse what was done in udsSupportAddFDToEventLoop().
2782 CFSocketEventSource
*iSource
;
2784 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2786 if (fd
== iSource
->fd
)
2788 RemoveFromList(&gEventSources
, iSource
);
2789 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2790 CFRunLoopSourceInvalidate(iSource
->RLS
);
2791 CFRelease(iSource
->RLS
);
2792 CFSocketInvalidate(iSource
->cfs
); // Note: Also closes the underlying socket
2793 CFRelease(iSource
->cfs
);
2795 return mStatus_NoError
;
2798 return mStatus_NoSuchNameErr
;
2801 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2802 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2803 asm(".desc ___crashreporter_info__, 0x10");
2805 // For convenience when using the "strings" command, this is the last thing in the file
2806 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";