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.255.2.1 2005/07/22 21:45:04 ksekar
40 Fix GCC 4.0/Intel compiler warnings
42 Revision 1.255 2005/03/09 00:48:43 cheshire
43 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
44 Move "m->p->NetworkChanged = 0;" line from caller to callee
46 Revision 1.254 2005/03/03 04:34:19 cheshire
47 <rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
49 Revision 1.253 2005/03/03 03:55:09 cheshire
50 <rdar://problem/3862944> Name collision notifications should be localized
52 Revision 1.252 2005/02/23 02:29:17 cheshire
53 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
54 Minor refinements, better variable names, improved comments
56 Revision 1.251 2005/02/21 21:31:24 ksekar
57 <rdar://problem/4015162> changed LogMsg to debugf
59 Revision 1.250 2005/02/19 01:25:04 cheshire
60 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
63 Revision 1.249 2005/02/19 00:28:45 cheshire
64 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
66 Revision 1.248 2005/02/19 00:18:34 cheshire
67 Confusing variable name -- alertMessage should be called alertHeader
69 Revision 1.247 2005/02/15 02:13:49 cheshire
70 If we did registerBootstrapService() when starting, then we must do
71 destroyBootstrapService() before exiting, or Mach init will keep restarting us.
73 Revision 1.246 2005/02/03 00:44:37 cheshire
74 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
76 Revision 1.245 2005/02/01 19:56:47 ksekar
77 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
79 Revision 1.244 2005/01/28 00:34:49 cheshire
80 Turn off "Starting time value" log message
82 Revision 1.243 2005/01/27 17:46:58 cheshire
83 Added comment about CFSocketInvalidate closing the underlying socket
85 Revision 1.242 2005/01/27 00:10:58 cheshire
86 <rdar://problem/3967867> Name change log messages every time machine boots
88 Revision 1.241 2005/01/25 17:28:06 ksekar
89 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
91 Revision 1.240 2005/01/21 02:39:18 cheshire
92 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
94 Revision 1.239 2005/01/20 00:25:01 cheshire
95 Improve validatelists() log message generation
97 Revision 1.238 2005/01/19 19:15:35 ksekar
98 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
100 Revision 1.237 2005/01/19 03:33:09 cheshire
101 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
103 Revision 1.236 2005/01/19 03:16:38 cheshire
104 <rdar://problem/3961051> CPU Spin in mDNSResponder
105 Improve detail of "Task Scheduling Error" diagnostic messages
107 Revision 1.235 2005/01/15 00:56:41 ksekar
108 <rdar://problem/3954575> Unicast services don't disappear when logging
111 Revision 1.234 2005/01/10 03:42:30 ksekar
114 Revision 1.233 2004/12/18 00:53:46 cheshire
115 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
117 Revision 1.232 2004/12/17 23:37:48 cheshire
118 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
119 (and other repetitive configuration changes)
121 Revision 1.231 2004/12/17 04:13:38 cheshire
122 Removed debugging check
124 Revision 1.230 2004/12/17 04:09:30 cheshire
125 <rdar://problem/3191011> Switch mDNSResponder to launchd
127 Revision 1.229 2004/12/16 21:51:36 cheshire
128 Remove some startup messages
130 Revision 1.228 2004/12/16 20:13:01 cheshire
131 <rdar://problem/3324626> Cache memory management improvements
133 Revision 1.227 2004/12/10 13:52:57 cheshire
134 <rdar://problem/3909995> Turn off SIGPIPE signals
136 Revision 1.226 2004/12/10 05:27:26 cheshire
137 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
139 Revision 1.225 2004/12/10 04:28:29 cheshire
140 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
142 Revision 1.224 2004/12/10 00:41:05 cheshire
143 Adjust alignment of log messages
145 Revision 1.223 2004/12/07 20:42:34 cheshire
146 Add explicit context parameter to mDNS_RemoveRecordFromService()
148 Revision 1.222 2004/12/06 21:15:23 ksekar
149 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
151 Revision 1.221 2004/11/30 03:24:04 cheshire
152 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
154 Revision 1.220 2004/11/29 23:34:31 cheshire
155 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
156 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
157 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
159 Revision 1.219 2004/11/25 01:00:56 cheshire
160 Checkin 1.217 not necessary
162 Revision 1.218 2004/11/24 20:27:19 cheshire
163 Add missing "err" parameter in LogMsg() call
165 Revision 1.217 2004/11/24 17:55:01 ksekar
166 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
168 Revision 1.216 2004/11/24 00:10:44 cheshire
169 <rdar://problem/3869241> For unicast operations, verify that service types are legal
171 Revision 1.215 2004/11/23 22:33:01 cheshire
172 <rdar://problem/3654910> Remove temporary workaround code for iChat
174 Revision 1.214 2004/11/23 22:13:59 cheshire
175 <rdar://problem/3886293> Subtype advertising broken for Mach API
177 Revision 1.213 2004/11/23 06:12:55 cheshire
178 <rdar://problem/3871405> Update wording for name conflict dialogs
180 Revision 1.212 2004/11/23 05:15:37 cheshire
181 <rdar://problem/3875830> Computer Name in use message garbled
183 Revision 1.211 2004/11/23 05:00:41 cheshire
184 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
186 Revision 1.210 2004/11/03 03:45:17 cheshire
187 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
189 Revision 1.209 2004/11/03 02:25:50 cheshire
190 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
192 Revision 1.208 2004/11/03 01:54:14 cheshire
193 Update debugging messages
195 Revision 1.207 2004/11/02 23:58:19 cheshire
196 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
198 Revision 1.206 2004/10/28 02:40:47 cheshire
199 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
201 Revision 1.205 2004/10/28 02:21:01 cheshire
202 <rdar://problem/3856500> Improve mDNSResponder signal handling
203 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
204 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
206 Revision 1.204 2004/10/27 01:57:21 cheshire
207 Add check of m->p->InterfaceList
209 Revision 1.203 2004/10/26 04:31:44 cheshire
210 Rename CountSubTypes() as ChopSubTypes()
212 Revision 1.202 2004/10/26 01:29:18 cheshire
213 Use "#if 0" instead of commenting out code
215 Revision 1.201 2004/10/25 21:41:39 ksekar
216 <rdar://problem/3852958> wide-area name conflicts can cause crash
218 Revision 1.200 2004/10/22 01:03:55 cheshire
219 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
220 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
222 Revision 1.199 2004/10/19 21:33:19 cheshire
223 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
224 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
225 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
227 Revision 1.198 2004/10/15 23:00:18 ksekar
228 <rdar://problem/3799242> Need to update LLQs on location changes
230 Revision 1.197 2004/10/12 23:38:59 ksekar
231 <rdar://problem/3837065> remove unnecessary log message
233 Revision 1.196 2004/10/04 05:56:04 cheshire
234 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
236 Revision 1.195 2004/09/30 00:24:59 ksekar
237 <rdar://problem/3695802> Dynamically update default registration domains on config change
239 Revision 1.194 2004/09/26 23:20:35 ksekar
240 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
242 Revision 1.193 2004/09/23 23:35:27 cheshire
245 Revision 1.192 2004/09/21 23:40:12 ksekar
246 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
248 Revision 1.191 2004/09/21 21:05:12 cheshire
249 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
250 into mDNSShared/uds_daemon.c
252 Revision 1.190 2004/09/21 19:51:15 cheshire
253 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
255 Revision 1.189 2004/09/21 18:17:23 cheshire
256 <rdar://problem/3785400> Add version info to mDNSResponder
258 Revision 1.188 2004/09/20 21:45:27 ksekar
261 Revision 1.187 2004/09/17 01:08:52 cheshire
262 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
263 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
264 declared in that file are ONLY appropriate to single-address-space embedded applications.
265 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
267 Revision 1.186 2004/09/16 00:24:49 cheshire
268 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
270 Revision 1.185 2004/08/25 02:01:45 cheshire
271 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
273 Revision 1.184 2004/08/19 19:04:12 ksekar
274 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
276 Revision 1.183 2004/08/14 03:22:42 cheshire
277 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
278 Add GetUserSpecifiedDDNSName() routine
279 Convert ServiceRegDomain to domainname instead of C string
280 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
282 Revision 1.182 2004/08/13 23:57:59 cheshire
283 Get rid of non-portable "_UNUSED"
285 Revision 1.181 2004/08/11 02:02:26 cheshire
286 Remove "mDNS *globalInstance" parameter from udsserver_init();
287 Move CheckForDuplicateRegistrations to uds_daemon.c
289 Revision 1.180 2004/07/13 21:24:25 rpantos
290 Fix for <rdar://problem/3701120>.
292 Revision 1.179 2004/06/19 00:02:54 cheshire
293 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
295 Revision 1.178 2004/06/18 19:10:00 cheshire
296 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
298 Revision 1.177 2004/06/16 23:14:46 ksekar
299 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
301 Revision 1.176 2004/06/11 20:27:42 cheshire
302 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
304 Revision 1.175 2004/06/10 20:23:21 cheshire
305 Also list interfaces in SIGINFO output
307 Revision 1.174 2004/06/08 18:54:48 ksekar
308 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
310 Revision 1.173 2004/06/08 17:35:12 cheshire
311 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
313 Revision 1.172 2004/06/05 00:04:26 cheshire
314 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
316 Revision 1.171 2004/06/04 08:58:30 ksekar
317 <rdar://problem/3668624>: Keychain integration for secure dynamic update
319 Revision 1.170 2004/05/30 20:01:50 ksekar
320 <rdar://problem/3668635>: wide-area default registrations should be in
321 .local too - fixed service registration when clients pass an explicit
322 domain (broken by previous checkin)
324 Revision 1.169 2004/05/30 01:30:16 ksekar
325 <rdar://problem/3668635>: wide-area default registrations should be in
328 Revision 1.168 2004/05/18 23:51:26 cheshire
329 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
331 Revision 1.167 2004/05/14 16:39:47 ksekar
332 Browse for iChat locally for now.
334 Revision 1.166 2004/05/13 21:33:52 ksekar
335 Clean up non-local registration control via config file. Force iChat
336 registrations to be local for now.
338 Revision 1.165 2004/05/13 04:54:20 ksekar
339 Unified list copy/free code. Added symetric list for
341 Revision 1.164 2004/05/12 22:03:08 ksekar
342 Made GetSearchDomainList a true platform-layer call (declaration moved
343 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
344 only on non-OSX platforms. Changed call to return a copy of the list
345 to avoid shared memory issues. Added a routine to free the list.
347 Revision 1.163 2004/05/12 02:03:25 ksekar
348 Non-local domains will only be browsed by default, and show up in
349 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
351 Revision 1.162 2004/04/14 23:09:29 ksekar
352 Support for TSIG signed dynamic updates.
354 Revision 1.161 2004/04/07 01:20:04 cheshire
355 Hash slot value should be unsigned
357 Revision 1.160 2004/04/06 19:51:24 cheshire
358 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
359 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
361 Revision 1.159 2004/04/03 01:36:55 cheshire
362 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
363 If "nobody" user doesn't exist, log a message and continue as "root"
365 Revision 1.158 2004/04/02 21:39:05 cheshire
366 Fix errors in comments
368 Revision 1.157 2004/03/19 18:49:10 ksekar
369 Increased size check in freeL() to account for LargeCacheRecord
370 structs larger than 8k
372 Revision 1.156 2004/03/19 18:19:19 ksekar
373 Fixed daemon.c to compile with malloc debugging turned on.
375 Revision 1.155 2004/03/13 01:57:34 ksekar
376 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
378 Revision 1.154 2004/03/12 08:42:47 cheshire
379 <rdar://problem/3548256>: Should not allow empty string for resolve domain
381 Revision 1.153 2004/03/12 08:08:51 cheshire
384 Revision 1.152 2004/02/05 19:39:29 cheshire
385 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
386 so that all platforms get this functionality
388 Revision 1.151 2004/02/03 22:35:34 cheshire
389 <rdar://problem/3548256>: Should not allow empty string for resolve domain
391 Revision 1.150 2004/01/28 21:14:23 cheshire
392 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
394 Revision 1.149 2004/01/28 02:30:08 ksekar
395 Added default Search Domains to unicast browsing, controlled via
396 Networking sharing prefs pane. Stopped sending unicast messages on
397 every interface. Fixed unicast resolving via mach-port API.
399 Revision 1.148 2004/01/25 00:03:20 cheshire
400 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
402 Revision 1.147 2004/01/19 19:51:46 cheshire
403 Fix compiler error (mixed declarations and code) on some versions of Linux
405 Revision 1.146 2003/12/08 21:00:46 rpantos
406 Changes to support mDNSResponder on Linux.
408 Revision 1.145 2003/12/05 22:08:07 cheshire
409 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
411 Revision 1.144 2003/11/19 23:21:08 ksekar
412 <rdar://problem/3486646>: config change handler not called for dns-sd services
414 Revision 1.143 2003/11/14 21:18:32 cheshire
415 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
416 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
418 Revision 1.142 2003/11/08 22:18:29 cheshire
419 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
421 Revision 1.141 2003/11/07 02:30:57 cheshire
422 Also check per-slot cache use counts in SIGINFO state log
424 Revision 1.140 2003/10/21 19:58:26 cheshire
425 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
427 Revision 1.139 2003/10/21 00:10:18 rpantos
428 <rdar://problem/3409401>: mDNSResponder should not run as root
430 Revision 1.138 2003/10/07 20:16:58 cheshire
431 Shorten syslog message a bit
433 Revision 1.137 2003/09/23 02:12:43 cheshire
434 Also include port number in list of services registered via new UDS API
436 Revision 1.136 2003/09/23 02:07:25 cheshire
437 Include port number in DNSServiceRegistration START/STOP messages
439 Revision 1.135 2003/09/23 01:34:02 cheshire
440 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
442 Revision 1.134 2003/08/21 20:01:37 cheshire
443 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
445 Revision 1.133 2003/08/20 23:39:31 cheshire
446 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
448 Revision 1.132 2003/08/20 01:44:56 cheshire
449 Fix errors in LogOperation() calls (only used for debugging)
451 Revision 1.131 2003/08/19 05:39:43 cheshire
452 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
454 Revision 1.130 2003/08/16 03:39:01 cheshire
455 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
457 Revision 1.129 2003/08/15 20:16:03 cheshire
458 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
459 We want to avoid touching the rdata pages, so we don't page them in.
460 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
461 Moved this from the RData to the ResourceRecord object.
462 2. To avoid unnecessarily touching the rdata just to compare it,
463 compute a hash of the rdata and store the hash in the ResourceRecord object.
465 Revision 1.128 2003/08/14 19:30:36 cheshire
466 <rdar://problem/3378473> Include list of cache records in SIGINFO output
468 Revision 1.127 2003/08/14 02:18:21 cheshire
469 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
471 Revision 1.126 2003/08/12 19:56:25 cheshire
474 Revision 1.125 2003/08/08 18:36:04 cheshire
475 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
477 Revision 1.124 2003/07/25 18:28:23 cheshire
478 Minor fix to error messages in syslog: Display string parameters with quotes
480 Revision 1.123 2003/07/23 17:45:28 cheshire
481 <rdar://problem/3339388> mDNSResponder leaks a bit
482 Don't allocate memory for the reply until after we've verified that the reply is valid
484 Revision 1.122 2003/07/23 00:00:04 cheshire
487 Revision 1.121 2003/07/20 03:38:51 ksekar
488 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
490 Revision 1.120 2003/07/18 00:30:00 cheshire
491 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
493 Revision 1.119 2003/07/17 19:08:58 cheshire
494 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
496 Revision 1.118 2003/07/15 21:12:28 cheshire
497 Added extra debugging checks in validatelists() (not used in final shipping version)
499 Revision 1.117 2003/07/15 01:55:15 cheshire
500 <rdar://problem/3315777> Need to implement service registration with subtypes
502 Revision 1.116 2003/07/02 21:19:51 cheshire
503 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
505 Revision 1.115 2003/07/02 02:41:24 cheshire
506 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
508 Revision 1.114 2003/07/01 21:10:20 cheshire
509 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
511 Revision 1.113 2003/06/28 17:27:43 vlubet
512 <rdar://problem/3221246> Redirect standard input, standard output, and
513 standard error file descriptors to /dev/null just like any other
516 Revision 1.112 2003/06/25 23:42:19 ksekar
517 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
518 Reviewed by: Stuart Cheshire
519 Added files necessary to implement Unix domain sockets based enhanced
520 DNS-SD APIs, and integrated with existing Mach-port based daemon.
522 Revision 1.111 2003/06/11 01:02:43 cheshire
523 <rdar://problem/3287858> mDNSResponder binary compatibility
524 Make single binary that can run on both Jaguar and Panther.
526 Revision 1.110 2003/06/10 01:14:11 cheshire
527 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
529 Revision 1.109 2003/06/06 19:53:43 cheshire
530 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
531 (Global search-and-replace; no functional change to code execution.)
533 Revision 1.108 2003/06/06 14:08:06 cheshire
534 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
536 Revision 1.107 2003/05/29 05:44:55 cheshire
537 Minor fixes to log messages
539 Revision 1.106 2003/05/27 18:30:55 cheshire
540 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
541 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
543 Revision 1.105 2003/05/26 03:21:29 cheshire
544 Tidy up address structure naming:
545 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
546 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
547 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
549 Revision 1.104 2003/05/26 00:42:06 cheshire
550 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
552 Revision 1.103 2003/05/23 23:07:44 cheshire
553 <rdar://problem/3268199> Must not write to stderr when running as daemon
555 Revision 1.102 2003/05/22 01:32:31 cheshire
556 Fix typo in Log message format string
558 Revision 1.101 2003/05/22 00:26:55 cheshire
559 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
560 Modify error message to explain that this is technically legal, but may indicate a bug.
562 Revision 1.100 2003/05/21 21:02:24 ksekar
563 <rdar://problem/3247035>: Service should be prefixed
564 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
565 Mach message port to "com.apple.mDNSResponder.
567 Revision 1.99 2003/05/21 17:33:49 cheshire
568 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
570 Revision 1.98 2003/05/20 00:33:07 cheshire
571 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
572 SIGHUP now writes state summary to syslog
574 Revision 1.97 2003/05/08 00:19:08 cheshire
575 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
577 Revision 1.96 2003/05/07 22:10:46 cheshire
578 <rdar://problem/3250330> Add a few more error logging messages
580 Revision 1.95 2003/05/07 19:20:17 cheshire
581 <rdar://problem/3251391> Add version number to mDNSResponder builds
583 Revision 1.94 2003/05/07 00:28:18 cheshire
584 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
586 Revision 1.93 2003/05/06 00:00:49 cheshire
587 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
589 Revision 1.92 2003/04/04 20:38:57 cheshire
594 #include <mach/mach.h>
595 #include <mach/mach_error.h>
596 #include <servers/bootstrap.h>
597 #include <sys/types.h>
602 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
604 #include "DNSServiceDiscoveryRequestServer.h"
605 #include "DNSServiceDiscoveryReply.h"
607 #include "DNSCommon.h"
608 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
610 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
612 #include "GenLinkedList.h"
614 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
616 //*************************************************************************************************************
619 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
620 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
621 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
622 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
623 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
625 //*************************************************************************************************************
628 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
629 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
630 static mDNS_PlatformSupport PlatformStorage
;
632 // Start off with a default cache of 16K (about 100 records)
633 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
634 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
636 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
637 static mach_port_t client_death_port
= MACH_PORT_NULL
;
638 static mach_port_t signal_port
= MACH_PORT_NULL
;
639 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
641 // mDNS Mach Message Timeout, in milliseconds.
642 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
643 // fails to service its mach message queue, but long enough to give a well-written
644 // client a chance to service its mach message queue without getting cut off.
645 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
646 // even extra-slow clients a fair chance before we cut them off.
647 #define MDNS_MM_TIMEOUT 250
649 static int restarting_via_mach_init
= 0;
650 static int started_via_launchdaemon
= 0;
654 //*************************************************************************************************************
655 // Active client list structures
657 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
658 struct DNSServiceDomainEnumeration_struct
660 DNSServiceDomainEnumeration
*next
;
661 mach_port_t ClientMachPort
;
662 DNSQuestion dom
; // Question asking for domains
663 DNSQuestion def
; // Question asking for default domain
666 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
667 struct DNSServiceBrowserResult_struct
669 DNSServiceBrowserResult
*next
;
674 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
676 typedef struct DNSServiceBrowserQuestion
678 struct DNSServiceBrowserQuestion
*next
;
681 } DNSServiceBrowserQuestion
;
683 struct DNSServiceBrowser_struct
685 DNSServiceBrowser
*next
;
686 mach_port_t ClientMachPort
;
687 DNSServiceBrowserQuestion
*qlist
;
688 DNSServiceBrowserResult
*results
;
690 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
691 domainname type
; // registration type
694 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
695 struct DNSServiceResolver_struct
697 DNSServiceResolver
*next
;
698 mach_port_t ClientMachPort
;
704 // A single registered service: ServiceRecordSet + bookkeeping
705 // Note that we duplicate some fields from parent DNSServiceRegistration object
706 // to facilitate cleanup, when instances and parent may be deallocated at different times.
707 typedef struct ServiceInstance
709 struct ServiceInstance
*next
;
710 mach_port_t ClientMachPort
;
711 mDNSBool autoname
; // Set if this name is tied to the Computer Name
712 mDNSBool autorename
; // Set if we just got a name conflict and now need to automatically pick a new name
715 ServiceRecordSet srs
;
716 // Don't add any fields after ServiceRecordSet.
717 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
720 // A client-created service. May reference several ServiceInstance objects if default
721 // settings cause registration in multiple domains.
722 typedef struct DNSServiceRegistration
724 struct DNSServiceRegistration
*next
;
725 mach_port_t ClientMachPort
;
726 mDNSBool DefaultDomain
;
730 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
731 domainlabel name
; // used only if autoname is false
734 unsigned char txtinfo
[1024];
737 ServiceInstance
*regs
;
738 } DNSServiceRegistration
;
740 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
741 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
742 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
743 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
745 //*************************************************************************************************************
746 // General Utility Functions
748 #if MACOSX_MDNS_MALLOC_DEBUGGING
750 char _malloc_options
[] = "AXZ";
752 mDNSlocal
void validatelists(mDNS
*const m
)
754 DNSServiceDomainEnumeration
*e
;
755 DNSServiceBrowser
*b
;
756 DNSServiceResolver
*l
;
757 DNSServiceRegistration
*r
;
763 NetworkInterfaceInfoOSX
*i
;
765 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
766 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
767 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
);
769 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
770 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
771 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
);
773 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
774 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
775 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
);
777 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
778 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
779 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
);
781 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
783 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
784 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
785 if (rr
->resrec
.name
!= &rr
->namestorage
)
786 LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
787 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
790 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
791 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
792 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
794 for (q
= m
->Questions
; q
; q
=q
->next
)
795 if (q
->ThisQInterval
== (mDNSs32
)~0)
796 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
);
798 FORALL_CACHERECORDS(slot
, cg
, cr
)
799 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
800 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->resrec
.RecordType
);
802 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
804 LogMsg("!!!! InterfaceList: %p is garbage !!!!", i
);
807 void *mallocL(char *msg
, unsigned int size
)
809 unsigned long *mem
= malloc(size
+8);
812 LogMsg("malloc( %s : %d ) failed", msg
, size
);
817 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
820 //bzero(&mem[2], size);
821 memset(&mem
[2], 0xFF, size
);
822 validatelists(&mDNSStorage
);
827 void freeL(char *msg
, void *x
)
830 LogMsg("free( %s @ NULL )!", msg
);
833 unsigned long *mem
= ((unsigned long *)x
) - 2;
834 if (mem
[0] != 0xDEAD1234)
835 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
837 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
838 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
839 //bzero(mem, mem[1]+8);
840 memset(mem
, 0xFF, mem
[1]+8);
841 validatelists(&mDNSStorage
);
848 //*************************************************************************************************************
849 // Client Death Detection
851 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
853 ServiceRecordSet
*s
= &x
->srs
;
854 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
858 e
->r
.RecordContext
= e
;
861 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
864 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
865 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
867 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
868 freeL("ServiceInstance", x
);
871 // AbortClient finds whatever client is identified by the given Mach port,
872 // stops whatever operation that client was doing, and frees its memory.
873 // In the case of a service registration, the actual freeing may be deferred
874 // until we get the mStatus_MemFree message, if necessary
875 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
877 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
878 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
879 DNSServiceResolver
**l
= &DNSServiceResolverList
;
880 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
882 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
885 DNSServiceDomainEnumeration
*x
= *e
;
888 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
889 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
890 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
891 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
892 freeL("DNSServiceDomainEnumeration", x
);
896 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
899 DNSServiceBrowser
*x
= *b
;
900 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
905 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
906 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
907 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
910 freeL("DNSServiceBrowserQuestion", freePtr
);
914 DNSServiceBrowserResult
*r
= x
->results
;
915 x
->results
= x
->results
->next
;
916 freeL("DNSServiceBrowserResult", r
);
918 freeL("DNSServiceBrowser", x
);
922 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
925 DNSServiceResolver
*x
= *l
;
928 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
929 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
930 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
931 freeL("DNSServiceResolver", x
);
935 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
938 ServiceInstance
*si
= NULL
;
939 DNSServiceRegistration
*x
= *r
;
945 ServiceInstance
*instance
= si
;
947 instance
->autorename
= mDNSfalse
;
948 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
);
949 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
951 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
952 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
953 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
954 // the list, so we should go ahead and free the memory right now
955 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
958 freeL("DNSServiceRegistration", x
);
962 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
965 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
967 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
969 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
970 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
971 DNSServiceResolver
*l
= DNSServiceResolverList
;
972 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
973 DNSServiceBrowserQuestion
*qptr
;
975 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
976 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
977 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
978 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
979 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
982 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
983 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
985 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
989 for (si
= r
->regs
; si
; si
= si
->next
) LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
991 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
996 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
998 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
999 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1000 DNSServiceResolver
*l
= DNSServiceResolverList
;
1001 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1002 DNSServiceBrowserQuestion
*qptr
;
1004 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1005 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1006 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1007 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1008 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
1011 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1012 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
1014 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
1015 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
1016 return(e
|| b
|| l
|| r
);
1019 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
1021 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
1022 (void)unusedport
; // Unused
1023 (void)size
; // Unused
1024 (void)info
; // Unused
1025 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1027 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
1028 AbortClient(deathMessage
->not_port
, NULL
);
1030 /* Deallocate the send right that came in the dead name notification */
1031 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
1035 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
1038 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
1039 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
1040 // If the port already died while we were thinking about it, then abort the operation right away
1041 if (r
!= KERN_SUCCESS
)
1042 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1045 //*************************************************************************************************************
1046 // Domain Enumeration
1048 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1050 kern_return_t status
;
1052 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1053 DNSServiceDomainEnumerationReplyResultType rt
;
1054 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1056 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1057 if (answer
->rrtype
!= kDNSType_PTR
) return;
1058 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1062 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1063 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1067 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1071 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1072 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1073 !AddRecord
? "RemoveDomain" :
1074 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1076 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1077 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1078 if (status
== MACH_SEND_TIMED_OUT
)
1079 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1082 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1085 // Check client parameter
1086 (void)unusedserver
; // Unused
1087 mStatus err
= mStatus_NoError
;
1088 const char *errormsg
= "Unknown";
1089 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1090 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1092 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1093 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1095 // Allocate memory, and handle failure
1096 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1097 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1099 // Set up object, and link into list
1100 x
->ClientMachPort
= client
;
1101 x
->next
= DNSServiceDomainEnumerationList
;
1102 DNSServiceDomainEnumerationList
= x
;
1104 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1107 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1108 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1109 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1111 // Succeeded: Wrap up and return
1112 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1113 EnableDeathNotificationForClient(client
, x
);
1114 return(mStatus_NoError
);
1117 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
1121 //*************************************************************************************************************
1122 // Browse for services
1124 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1128 if (answer
->rrtype
!= kDNSType_PTR
)
1129 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1132 domainname type
, domain
;
1133 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1135 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1136 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1140 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1141 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1143 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1144 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1146 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1147 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1150 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1151 DNSServiceBrowserResult
**p
= &browser
->results
;
1152 while (*p
) p
= &(*p
)->next
;
1156 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1158 mStatus err
= mStatus_NoError
;
1159 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1161 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1163 if (SameDomainName(&ptr
->q
.qname
, d
))
1164 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1167 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1168 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1169 AssignDomainName(&question
->domain
, d
);
1170 question
->next
= browser
->qlist
;
1171 browser
->qlist
= question
;
1172 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1173 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1174 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1178 mDNSexport
void DefaultBrowseDomainChanged(const domainname
*d
, mDNSBool add
)
1180 DNSServiceBrowser
*ptr
;
1182 debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
1183 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1185 if (ptr
->DefaultDomain
)
1189 mStatus err
= AddDomainToBrowser(ptr
, d
);
1190 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1194 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1197 if (SameDomainName(&(*q
)->domain
, d
))
1199 DNSServiceBrowserQuestion
*remove
= *q
;
1201 if (remove
->q
.LongLived
)
1203 // give goodbyes for known answers. note that since events are sent to client via udns_execute(),
1204 // we don't need to worry about the question being cancelled mid-loop
1205 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
1206 while (ka
) { remove
->q
.QuestionCallback(&mDNSStorage
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
1208 mDNS_StopBrowse(&mDNSStorage
, &remove
->q
);
1209 freeL("DNSServiceBrowserQuestion", remove
);
1214 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1220 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1221 DNSCString regtype
, DNSCString domain
)
1223 // Check client parameter
1224 (void)unusedserver
; // Unused
1225 mStatus err
= mStatus_NoError
;
1226 const char *errormsg
= "Unknown";
1227 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
1229 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1230 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1232 // Check other parameters
1235 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1236 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1237 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1238 { errormsg
= "Bad Service SubType"; goto badparam
; }
1239 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1241 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1242 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1244 // Allocate memory, and handle failure
1245 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1246 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1248 // Set up object, and link into list
1249 AssignDomainName(&x
->type
, &t
);
1250 x
->ClientMachPort
= client
;
1254 x
->next
= DNSServiceBrowserList
;
1255 DNSServiceBrowserList
= x
;
1259 // Start browser for an explicit domain
1260 x
->DefaultDomain
= mDNSfalse
;
1261 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1262 err
= AddDomainToBrowser(x
, &d
);
1263 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1267 // Start browser on all domains
1268 x
->DefaultDomain
= mDNStrue
;
1269 SearchDomains
= mDNSPlatformGetSearchDomainList();
1270 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1271 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1273 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1276 // only terminally bail if .local fails
1277 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1278 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1279 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1284 // Succeeded: Wrap up and return
1285 EnableDeathNotificationForClient(client
, x
);
1286 mDNS_FreeDNameList(SearchDomains
);
1287 return(mStatus_NoError
);
1290 err
= mStatus_BadParamErr
;
1292 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1293 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
1297 //*************************************************************************************************************
1298 // Resolve Service Info
1300 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1302 kern_return_t status
;
1303 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1304 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1305 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1306 struct sockaddr_storage interface
;
1307 struct sockaddr_storage address
;
1309 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1312 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1314 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1316 bzero(&interface
, sizeof(interface
));
1317 bzero(&address
, sizeof(address
));
1319 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1321 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1322 sin
->sin_len
= sizeof(*sin
);
1323 sin
->sin_family
= AF_INET
;
1325 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1327 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1329 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1330 sin6
->sin6_len
= sizeof(*sin6
);
1331 sin6
->sin6_family
= AF_INET6
;
1332 sin6
->sin6_flowinfo
= 0;
1333 sin6
->sin6_port
= 0;
1334 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1335 sin6
->sin6_scope_id
= ifx
->scope_id
;
1338 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1340 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1341 sin
->sin_len
= sizeof(*sin
);
1342 sin
->sin_family
= AF_INET
;
1343 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1344 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1348 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1349 sin6
->sin6_len
= sizeof(*sin6
);
1350 sin6
->sin6_family
= AF_INET6
;
1351 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1352 sin6
->sin6_flowinfo
= 0;
1353 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1354 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1357 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1358 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1359 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1360 // ASCII-1 characters are used in the C-string as boundary markers,
1361 // to indicate the boundaries between the original constituent P-strings.
1362 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1365 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1369 pstrlen
= query
->info
->TXTinfo
[i
];
1372 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1374 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1375 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1376 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1377 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1378 if (status
== MACH_SEND_TIMED_OUT
)
1379 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1382 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1383 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1385 // Check client parameter
1386 (void)unusedserver
; // Unused
1387 mStatus err
= mStatus_NoError
;
1388 const char *errormsg
= "Unknown";
1389 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1390 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1392 // Check other parameters
1394 domainname t
, d
, srv
;
1395 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1396 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1397 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1398 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1400 // Allocate memory, and handle failure
1401 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1402 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1404 // Set up object, and link into list
1405 x
->ClientMachPort
= client
;
1406 x
->i
.InterfaceID
= mDNSInterface_Any
;
1408 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1409 x
->next
= DNSServiceResolverList
;
1410 DNSServiceResolverList
= x
;
1413 LogOperation("%5d: DNSServiceResolver(%##s) START", client
, x
->i
.name
.c
);
1414 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1415 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1417 // Succeeded: Wrap up and return
1418 EnableDeathNotificationForClient(client
, x
);
1419 return(mStatus_NoError
);
1422 err
= mStatus_BadParamErr
;
1424 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1428 //*************************************************************************************************************
1431 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1433 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1436 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1438 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1440 if (result
== mStatus_NoError
)
1442 kern_return_t status
;
1443 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1444 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1445 if (status
== MACH_SEND_TIMED_OUT
)
1446 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1447 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1448 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1451 else if (result
== mStatus_NameConflict
)
1453 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1454 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1455 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1456 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1458 // On conflict for an autoname service, rename and reregister *all* autoname services
1459 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1460 m
->MainCallback(m
, mStatus_ConfigChanged
);
1462 else if (si
->autoname
)
1464 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1469 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1470 // of their registration in the usual way (which we will catch via client death notification).
1471 // If the Mach queue is full, we forcibly abort the client immediately.
1472 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1473 if (status
== MACH_SEND_TIMED_OUT
)
1474 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1478 else if (result
== mStatus_MemFree
)
1482 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1483 si
->autorename
= mDNSfalse
;
1484 si
->name
= m
->nicelabel
;
1485 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1489 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1490 DNSServiceRegistration
*r
;
1491 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1493 ServiceInstance
*sp
= r
->regs
, *prev
= NULL
;
1498 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
->c
);
1499 if (prev
) prev
->next
= sp
->next
;
1500 else r
->regs
= sp
->next
;
1508 FreeServiceInstance(si
);
1512 else if (result
!= mStatus_NATTraversal
)
1513 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1516 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1519 ServiceInstance
*si
= NULL
;
1520 AuthRecord
*SubTypes
= NULL
;
1522 for (si
= x
->regs
; si
; si
= si
->next
)
1524 if (SameDomainName(&si
->domain
, domain
))
1525 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1528 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1529 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1531 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1532 if (!si
) return mStatus_NoMemoryErr
;
1534 si
->ClientMachPort
= x
->ClientMachPort
;
1535 si
->autorename
= mDNSfalse
;
1536 si
->autoname
= x
->autoname
;
1537 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1538 si
->domain
= *domain
;
1540 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
);
1548 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1549 freeL("ServiceInstance", si
);
1554 mDNSexport
void DefaultRegDomainChanged(const domainname
*d
, mDNSBool add
)
1556 DNSServiceRegistration
*reg
;
1558 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1560 if (reg
->DefaultDomain
)
1564 AddServiceInstance(reg
, d
);
1568 ServiceInstance
*si
= reg
->regs
, *prev
= NULL
;
1571 if (SameDomainName(&si
->domain
, d
))
1573 if (prev
) prev
->next
= si
->next
;
1574 else reg
->regs
= si
->next
;
1575 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
))
1576 FreeServiceInstance(si
); // only free memory synchronously on error
1582 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1588 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1589 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1591 (void)unusedserver
; // Unused
1592 mStatus err
= mStatus_NoError
;
1593 const char *errormsg
= "Unknown";
1595 // older versions of this code passed the port via mach IPC as an int.
1596 // we continue to pass it as 4 bytes to maintain binary compatibility,
1597 // but now ensure that the network byte order is preserved by using a struct
1599 port
.b
[0] = IpPort
.bytes
[2];
1600 port
.b
[1] = IpPort
.bytes
[3];
1602 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1603 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1605 // Check for sub-types after the service type
1606 size_t reglen
= strlen(regtype
) + 1;
1607 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1608 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1609 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1611 // Check other parameters
1615 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1616 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1617 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1618 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1619 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1621 unsigned char txtinfo
[1024] = "";
1622 unsigned int data_len
= 0;
1623 unsigned int size
= sizeof(RDataBody
);
1624 unsigned char *pstring
= &txtinfo
[data_len
];
1625 char *ptr
= txtRecord
;
1627 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1628 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1629 // Hence we have to convert the C-string to a P-string.
1630 // ASCII-1 characters are allowed in the C-string as boundary markers,
1631 // so that a single C-string can be used to represent one or more P-strings.
1634 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1635 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1637 pstring
= &txtinfo
[data_len
];
1643 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1644 pstring
[++pstring
[0]] = *ptr
++;
1649 if (size
< data_len
)
1652 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1653 // a port number of zero. When two instances of the protected client are allowed to run on one
1654 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1655 if (port
.NotAnInteger
)
1657 int count
= CountExistingRegistrations(&srv
, port
);
1659 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1660 client
, count
+1, srv
.c
, mDNSVal16(port
));
1663 // Allocate memory, and handle failure
1664 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1665 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1666 bzero(x
, sizeof(*x
));
1668 // Set up object, and link into list
1669 x
->ClientMachPort
= client
;
1670 x
->DefaultDomain
= !domain
[0];
1671 x
->autoname
= (!name
[0]);
1673 x
->NumSubTypes
= NumSubTypes
;
1674 memcpy(x
->regtype
, regtype
, reglen
);
1678 memcpy(x
->txtinfo
, txtinfo
, 1024);
1679 x
->txt_len
= data_len
;
1683 x
->next
= DNSServiceRegistrationList
;
1684 DNSServiceRegistrationList
= x
;
1686 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1687 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1689 err
= AddServiceInstance(x
, &d
);
1690 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1692 if (x
->DefaultDomain
)
1694 DNameListElem
*ptr
, *regdomains
= mDNSPlatformGetRegDomainList();
1695 for (ptr
= regdomains
; ptr
; ptr
= ptr
->next
)
1696 AddServiceInstance(x
, &ptr
->name
);
1697 mDNS_FreeDNameList(regdomains
);
1700 // Succeeded: Wrap up and return
1701 EnableDeathNotificationForClient(client
, x
);
1702 return(mStatus_NoError
);
1705 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1707 err
= mStatus_BadParamErr
;
1709 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1710 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1714 mDNSlocal CFUserNotificationRef gNotification
= NULL
;
1715 mDNSlocal CFRunLoopSourceRef gNotificationRLS
= NULL
;
1716 mDNSlocal domainlabel gNotificationPrefHostLabel
; // The prefs as they were the last time we saw them
1717 mDNSlocal domainlabel gNotificationPrefNiceLabel
;
1718 mDNSlocal domainlabel gNotificationUserHostLabel
; // The prefs as they were the last time the user changed them
1719 mDNSlocal domainlabel gNotificationUserNiceLabel
;
1721 mDNSlocal
void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
1723 (void)responseFlags
; // Unused
1724 if (userNotification
!= gNotification
) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
1725 if (gNotificationRLS
)
1727 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1728 CFRelease(gNotificationRLS
);
1729 gNotificationRLS
= NULL
;
1730 CFRelease(gNotification
);
1731 gNotification
= NULL
;
1733 // By dismissing the alert, the user has conceptually acknowleged the rename.
1734 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
1735 // If we get *another* conflict, the new alert should refer to the 'old'.
1736 // name as now being "computer-2.local", not "computer.local"
1737 gNotificationUserHostLabel
= gNotificationPrefHostLabel
;
1738 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
;
1741 mDNSlocal
void ShowNameConflictNotification(CFStringRef header
, CFStringRef subtext
)
1743 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1744 if (!dictionary
) return;
1745 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
1746 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
1748 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
1749 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
1751 if (gNotification
) // If notification already on-screen, update it in place
1752 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
1753 else // else, we need to create it
1756 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
1757 if (!gNotification
) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
1758 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
1759 if (!gNotificationRLS
) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
1760 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1763 CFRelease(dictionary
);
1766 // This updates either the text of the field currently labelled "Local Hostname",
1767 // or the text of the field currently labelled "Computer Name"
1768 // in the Sharing Prefs Control Panel
1769 mDNSlocal
void RecordUpdatedName(const mDNS
*const m
, const domainlabel
*const olddl
, const domainlabel
*const newdl
,
1770 const char *const msg
, const char *const suffix
, const CFStringRef subtext
)
1772 char oldname
[MAX_DOMAIN_LABEL
+1];
1773 char newname
[MAX_DOMAIN_LABEL
+1];
1774 ConvertDomainLabelToCString_unescaped(olddl
, oldname
);
1775 ConvertDomainLabelToCString_unescaped(newdl
, newname
);
1776 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
1777 const CFStringRef cfnewname
= CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
);
1778 const CFStringRef f1
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1779 const CFStringRef f2
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1780 const SCPreferencesRef session
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
);
1781 if (!cfoldname
|| !cfnewname
|| !f1
|| !f2
|| !session
|| !SCPreferencesLock(session
, 0)) // If we can't get the lock don't wait
1782 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1785 const CFStringRef s0
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1786 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
);
1787 const CFStringRef s2
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
);
1788 // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
1789 // element of the array individually for us, and then concatenate the results to make the final message.
1790 // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
1791 // On Panther this does not work, so we just build the string directly, and it will not be translated.
1792 const CFMutableStringRef alertHeader
=
1793 (OSXVers
< 8) ? CFStringCreateMutable(NULL
, 0) : (CFMutableStringRef
)CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1795 if (newdl
== &gNotificationPrefHostLabel
) result
= SCPreferencesSetLocalHostName(session
, cfnewname
);
1796 else result
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
);
1797 if (!result
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0
|| !s1
|| !s2
|| !alertHeader
)
1798 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1799 else if (m
->p
->NotifyUser
)
1803 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
1806 CFRelease(userName
);
1807 typedef void CFStringAppendFN(CFMutableStringRef theString
, CFStringRef appendedString
);
1808 CFStringAppendFN
*const append
= (OSXVers
< 8) ? &CFStringAppend
: (CFStringAppendFN
*)&CFArrayAppendValue
;
1809 append(alertHeader
, s0
);
1810 append(alertHeader
, s1
);
1811 append(alertHeader
, CFSTR("is already in use on this network."));
1812 append(alertHeader
, CFSTR(" "));
1813 append(alertHeader
, CFSTR("The name has been changed to"));
1814 append(alertHeader
, s2
);
1815 append(alertHeader
, CFSTR("automatically."));
1816 ShowNameConflictNotification(alertHeader
, subtext
);
1819 if (s0
) CFRelease(s0
);
1820 if (s1
) CFRelease(s1
);
1821 if (s2
) CFRelease(s2
);
1822 if (alertHeader
) CFRelease(alertHeader
);
1823 SCPreferencesUnlock(session
);
1825 if (cfoldname
) CFRelease(cfoldname
);
1826 if (cfnewname
) CFRelease(cfnewname
);
1827 if (f1
) CFRelease(f1
);
1828 if (f2
) CFRelease(f2
);
1829 if (session
) CFRelease(session
);
1832 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1835 if (result
== mStatus_NoError
)
1837 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1838 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1840 else if (result
== mStatus_ConfigChanged
)
1842 // If the user-specified hostlabel from System Configuration has changed since the last time
1843 // we saw it, and *we* didn't change it, then that implies that the user has changed it,
1844 // so we auto-dismiss the name conflict alert.
1845 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, gNotificationPrefHostLabel
.c
) ||
1846 !SameDomainLabel(m
->p
->usernicelabel
.c
, gNotificationPrefNiceLabel
.c
))
1848 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= m
->p
->userhostlabel
;
1849 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= m
->p
->usernicelabel
;
1850 // If we're showing a name conflict notification, and the user has manually edited
1851 // the name to remedy the conflict, we should now remove the notification window.
1852 if (gNotificationRLS
) CFUserNotificationCancel(gNotification
);
1855 DNSServiceRegistration
*r
;
1856 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1859 ServiceInstance
*si
;
1860 for (si
= r
->regs
; si
; si
= si
->next
)
1862 if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
))
1864 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1865 si
->autorename
= mDNStrue
;
1866 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1867 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1871 udsserver_handle_configchange();
1873 else if (result
== mStatus_GrowCache
)
1875 // Allocate another chunk of cache storage
1876 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1877 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1881 //*************************************************************************************************************
1882 // Add / Update / Remove records from existing Registration
1884 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1885 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1887 // Check client parameter
1889 mStatus err
= mStatus_NoError
;
1890 const char *errormsg
= "Unknown";
1891 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1892 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1893 ServiceInstance
*si
;
1895 (void)unusedserver
; // Unused
1896 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1897 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1899 // Check other parameters
1900 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1901 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1902 else size
= sizeof(RDataBody
);
1905 *reference
= (natural_t
)id
;
1906 for (si
= x
->regs
; si
; si
= si
->next
)
1908 // Allocate memory, and handle failure
1909 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1910 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1912 // Fill in type, length, and data of new record
1913 extra
->r
.resrec
.rrtype
= type
;
1914 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1915 extra
->r
.resrec
.rdlength
= data_len
;
1916 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1919 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1920 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1921 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1925 freeL("Extra Resource Record", extra
);
1926 errormsg
= "mDNS_AddRecordToService";
1930 extra
->ClientID
= id
;
1933 return mStatus_NoError
;
1936 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
1937 return mStatus_UnknownErr
;
1940 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1943 if (OldRData
!= &rr
->rdatastorage
)
1944 freeL("Old RData", OldRData
);
1947 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1949 // Check client parameter
1950 mStatus err
= mStatus_NoError
;
1951 const char *errormsg
= "Unknown";
1952 domainname
*name
= (domainname
*)"";
1954 name
= srs
->RR_SRV
.resrec
.name
;
1956 unsigned int size
= sizeof(RDataBody
);
1957 if (size
< data_len
)
1960 // Allocate memory, and handle failure
1961 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1962 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1964 // Fill in new length, and data
1965 newrdata
->MaxRDLength
= size
;
1966 memcpy(&newrdata
->u
, data
, data_len
);
1968 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1969 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1970 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1971 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
1974 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1975 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1977 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1980 errormsg
= "mDNS_Update";
1981 freeL("RData", newrdata
);
1984 return(mStatus_NoError
);
1987 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1991 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1992 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1994 // Check client parameter
1995 mStatus err
= mStatus_NoError
;
1996 const char *errormsg
= "Unknown";
1997 domainname
*name
= (domainname
*)"";
1998 ServiceInstance
*si
;
2000 (void)unusedserver
; // unused
2001 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2002 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2003 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2004 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2006 // Check other parameters
2007 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
2009 for (si
= x
->regs
; si
; si
= si
->next
)
2011 AuthRecord
*r
= NULL
;
2013 // Find the record we're updating. NULL reference means update the primary TXT record
2014 if (!reference
) r
= &si
->srs
.RR_TXT
;
2017 ExtraResourceRecord
*ptr
;
2018 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2020 if ((natural_t
)ptr
->ClientID
== reference
)
2021 { r
= &ptr
->r
; break; }
2023 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
2025 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
2026 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
2029 return mStatus_NoError
;
2032 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
2036 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
2038 domainname
*name
= srs
->RR_SRV
.resrec
.name
;
2039 mStatus err
= mStatus_NoError
;
2042 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
2044 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
2045 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
2050 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2051 natural_t reference
)
2053 // Check client parameter
2054 (void)unusedserver
; // Unused
2055 mStatus err
= mStatus_NoError
;
2056 const char *errormsg
= "Unknown";
2057 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2058 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2059 ServiceInstance
*si
;
2061 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2062 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2064 for (si
= x
->regs
; si
; si
= si
->next
)
2066 ExtraResourceRecord
*e
;
2067 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
2069 if ((natural_t
)e
->ClientID
== reference
)
2071 err
= RemoveRecord(&si
->srs
, e
, client
);
2075 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
2078 return mStatus_NoError
;
2081 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
2085 //*************************************************************************************************************
2088 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2090 mig_reply_error_t
*request
= msg
;
2091 mig_reply_error_t
*reply
;
2092 mach_msg_return_t mr
;
2094 (void)port
; // Unused
2095 (void)size
; // Unused
2096 (void)info
; // Unused
2098 /* allocate a reply buffer */
2099 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
2101 /* call the MiG server routine */
2102 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
2104 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
2106 if (reply
->RetCode
== MIG_NO_REPLY
)
2109 * This return code is a little tricky -- it appears that the
2110 * demux routine found an error of some sort, but since that
2111 * error would not normally get returned either to the local
2112 * user or the remote one, we pretend it's ok.
2114 CFAllocatorDeallocate(NULL
, reply
);
2119 * destroy any out-of-line data in the request buffer but don't destroy
2120 * the reply port right (since we need that to send an error message).
2122 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2123 mach_msg_destroy(&request
->Head
);
2126 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2128 /* no reply port, so destroy the reply */
2129 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2130 mach_msg_destroy(&reply
->Head
);
2131 CFAllocatorDeallocate(NULL
, reply
);
2138 * We don't want to block indefinitely because the client
2139 * isn't receiving messages from the reply port.
2140 * If we have a send-once right for the reply port, then
2141 * this isn't a concern because the send won't block.
2142 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2143 * To avoid falling off the kernel's fast RPC path unnecessarily,
2144 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2147 options
= MACH_SEND_MSG
;
2148 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2149 options
|= MACH_SEND_TIMEOUT
;
2151 mr
= mach_msg(&reply
->Head
, /* msg */
2152 options
, /* option */
2153 reply
->Head
.msgh_size
, /* send_size */
2155 MACH_PORT_NULL
, /* rcv_name */
2156 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2157 MACH_PORT_NULL
); /* notify */
2159 /* Has a message error occurred? */
2162 case MACH_SEND_INVALID_DEST
:
2163 case MACH_SEND_TIMED_OUT
:
2164 /* the reply can't be delivered, so destroy it */
2165 mach_msg_destroy(&reply
->Head
);
2169 /* Includes success case. */
2173 CFAllocatorDeallocate(NULL
, reply
);
2176 mDNSlocal kern_return_t
registerBootstrapService()
2178 kern_return_t status
;
2179 mach_port_t service_send_port
, service_rcv_port
;
2181 debugf("Registering Bootstrap Service");
2184 * See if our service name is already registered and if we have privilege to check in.
2186 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2187 if (status
== KERN_SUCCESS
)
2190 * If so, we must be a followup instance of an already defined server. In that case,
2191 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2192 * that in case we have to unregister later (which requires the privilege port).
2194 server_priv_port
= bootstrap_port
;
2195 restarting_via_mach_init
= TRUE
;
2197 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2199 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2200 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2201 if (status
!= KERN_SUCCESS
) return status
;
2203 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2204 if (status
!= KERN_SUCCESS
)
2206 mach_port_deallocate(mach_task_self(), server_priv_port
);
2210 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2211 if (status
!= KERN_SUCCESS
)
2213 mach_port_deallocate(mach_task_self(), server_priv_port
);
2214 mach_port_deallocate(mach_task_self(), service_send_port
);
2217 assert(service_send_port
== service_rcv_port
);
2221 * We have no intention of responding to requests on the service port. We are not otherwise
2222 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2223 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2224 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2226 mach_port_destroy(mach_task_self(), service_rcv_port
);
2230 mDNSlocal kern_return_t
destroyBootstrapService()
2232 debugf("Destroying Bootstrap Service");
2233 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2236 mDNSlocal
void ExitCallback(int signal
)
2238 LogMsgIdent(mDNSResponderVersionString
, "stopping");
2240 debugf("ExitCallback");
2241 if (!mDNS_DebugMode
&& !started_via_launchdaemon
&& signal
!= SIGHUP
)
2242 destroyBootstrapService();
2244 debugf("ExitCallback: Aborting MIG clients");
2245 while (DNSServiceDomainEnumerationList
)
2246 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2247 while (DNSServiceBrowserList
)
2248 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2249 while (DNSServiceResolverList
)
2250 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2251 while (DNSServiceRegistrationList
)
2252 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2254 debugf("ExitCallback: mDNS_Close");
2255 mDNS_Close(&mDNSStorage
);
2256 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2260 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2261 mDNSlocal
void HandleSIG(int signal
)
2264 debugf("HandleSIG %d", signal
);
2265 mach_msg_header_t header
;
2266 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2267 header
.msgh_remote_port
= signal_port
;
2268 header
.msgh_local_port
= MACH_PORT_NULL
;
2269 header
.msgh_size
= sizeof(header
);
2270 header
.msgh_id
= signal
;
2271 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2273 LogMsg("HandleSIG %d: mach_msg_send failed", signal
);
2274 if (signal
== SIGHUP
|| signal
== SIGTERM
|| signal
== SIGINT
) exit(-1);
2278 mDNSlocal
void INFOCallback(void)
2280 mDNSs32 utc
= mDNSPlatformUTC();
2281 DNSServiceDomainEnumeration
*e
;
2282 DNSServiceBrowser
*b
;
2283 DNSServiceResolver
*l
;
2284 DNSServiceRegistration
*r
;
2285 NetworkInterfaceInfoOSX
*i
;
2287 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2289 udsserver_info(&mDNSStorage
);
2291 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2292 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2294 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2296 DNSServiceBrowserQuestion
*qptr
;
2297 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2298 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2300 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2301 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2303 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2305 ServiceInstance
*si
;
2306 for (si
= r
->regs
; si
; si
= si
->next
)
2307 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
));
2310 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2313 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
2314 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, utc
- i
->LastSeen
);
2316 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2317 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2318 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2319 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
2320 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
2321 i
->ifinfo
.InterfaceID
,
2322 i
->ifinfo
.Advertise
? "Adv" : " ",
2323 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2327 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2330 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2332 (void)port
; // Unused
2333 (void)size
; // Unused
2334 (void)info
; // Unused
2335 mach_msg_header_t
*m
= (mach_msg_header_t
*)msg
;
2340 case SIGTERM
: ExitCallback(m
->msgh_id
); break;
2341 case SIGINFO
: INFOCallback(); break;
2342 case SIGUSR1
: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2343 mDNSMacOSXNetworkChanged(&mDNSStorage
); break;
2344 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break;
2348 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2349 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2351 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2354 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2355 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2356 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2357 mach_port_t m_port
= CFMachPortGetPort(s_port
);
2358 char *MachServerName
= OSXVers
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2359 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2360 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2361 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2362 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2367 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2369 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2373 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2374 rrcachestorage
, RR_CACHE_SIZE
,
2375 mDNS_Init_AdvertiseLocalAddresses
,
2376 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2378 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2380 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= PlatformStorage
.userhostlabel
;
2381 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= PlatformStorage
.usernicelabel
;
2383 client_death_port
= CFMachPortGetPort(d_port
);
2384 signal_port
= CFMachPortGetPort(i_port
);
2386 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
2387 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
2388 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
2392 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2396 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2398 mDNSs32 now
= mDNS_TimeNow(m
);
2400 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2402 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2403 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2404 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2405 // we then systematically lose our own looped-back packets.
2406 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2408 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2409 mDNSs32 nextevent
= mDNS_Execute(m
);
2411 if (m
->p
->NetworkChanged
)
2412 if (nextevent
- m
->p
->NetworkChanged
> 0)
2413 nextevent
= m
->p
->NetworkChanged
;
2415 // 3. Deliver any waiting browse messages to clients
2416 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2420 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2421 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2422 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2423 DNSServiceBrowser
*x
= b
;
2425 if (x
->results
) // Try to deliver the list of results
2429 DNSServiceBrowserResult
*const r
= x
->results
;
2431 domainname type
, domain
;
2432 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2433 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2434 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2435 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2436 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2437 ConvertDomainNameToCString(&type
, ctype
);
2438 ConvertDomainNameToCString(&domain
, cdom
);
2439 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2440 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2441 // If we failed to send the mach message, try again in one second
2442 if (status
== MACH_SEND_TIMED_OUT
)
2444 if (nextevent
- now
> mDNSPlatformOneSecond
)
2445 nextevent
= now
+ mDNSPlatformOneSecond
;
2450 x
->lastsuccess
= now
;
2451 x
->results
= x
->results
->next
;
2452 freeL("DNSServiceBrowserResult", r
);
2455 // If this client hasn't read a single message in the last 60 seconds, abort it
2456 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2457 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2461 DNSServiceResolver
*l
;
2462 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2463 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2466 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2467 "This places considerable burden on the network.", l
->i
.name
.c
);
2470 if (m
->p
->NotifyUser
)
2472 if (m
->p
->NotifyUser
- now
< 0)
2474 if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2476 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2477 gNotificationPrefNiceLabel
= m
->p
->usernicelabel
= m
->nicelabel
;
2478 RecordUpdatedName(m
, &gNotificationUserNiceLabel
, &gNotificationPrefNiceLabel
, "The name of your computer", "",
2479 CFSTR("To change the name of your computer, open System Preferences and click Sharing. "
2480 "Then type the name in the Computer Name field."));
2481 // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2482 m
->p
->NotifyUser
= 0;
2484 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2486 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2487 gNotificationPrefHostLabel
= m
->p
->userhostlabel
= m
->hostlabel
;
2488 RecordUpdatedName(m
, &gNotificationUserHostLabel
, &gNotificationPrefHostLabel
, "This computer’s local hostname", ".local",
2489 CFSTR("To change the local hostname, open System Preferences and click Sharing. "
2490 "Then click Edit and type the name in the Local Hostname field."));
2492 m
->p
->NotifyUser
= 0;
2495 if (nextevent
- m
->p
->NotifyUser
> 0)
2496 nextevent
= m
->p
->NotifyUser
;
2502 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2506 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2508 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2509 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2510 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2511 if (m
->NewLocalOnlyQuestions
)
2512 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2513 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2514 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2515 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2516 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2517 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2518 #ifndef UNICAST_DISABLED
2519 if (m
->timenow
- m
->uDNS_info
.nextevent
>= 0)
2520 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m
->timenow
- m
->uDNS_info
.nextevent
);
2522 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2523 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2524 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2525 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2526 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2527 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2528 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2529 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2531 mDNS_Unlock(&mDNSStorage
);
2534 mDNSexport
int main(int argc
, char **argv
)
2537 kern_return_t status
;
2539 for (i
=1; i
<argc
; i
++)
2541 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2542 if (!strcmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2545 signal(SIGHUP
, HandleSIG
); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2546 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2547 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2548 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2549 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2550 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2552 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2553 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2555 registerBootstrapService();
2556 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2557 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2558 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2561 // Avoid unnecessarily duplicating a file descriptor to itself
2562 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2563 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2564 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2565 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2569 // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
2570 // The sooner we do this, the faster the machine will boot.
2571 status
= udsserver_init();
2572 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
2574 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2575 LogMsgIdent(mDNSResponderVersionString
, "starting");
2576 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
2577 status
= mDNSDaemonInitialize();
2579 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2580 // Now that we're finished with anything privileged, switch over to running as "nobody"
2581 const struct passwd
*pw
= getpwnam("nobody");
2585 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2590 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2592 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2594 // This is the main work loop:
2595 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2596 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2597 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2598 // (4) On wakeup we first process *all* events
2599 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2600 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2602 // 1. Before going into a blocking wait call and letting our process to go sleep,
2603 // call mDNSDaemonIdle to allow any deferred work to be completed.
2604 mDNSs32 nextevent
= mDNSDaemonIdle(&mDNSStorage
);
2605 nextevent
= udsserver_idle(nextevent
);
2607 // 2. Work out how long we expect to sleep before the next scheduled task
2608 mDNSs32 ticks
= nextevent
- mDNS_TimeNow(&mDNSStorage
);
2609 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2615 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2617 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2619 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2620 // (a) our next wakeup time, or (b) an event occurs.
2621 // The 'true' parameter makes it return after handling any event that occurs
2622 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2623 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2625 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2627 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2628 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2631 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2635 LogMsg("ERROR: CFRunLoopRun Exiting.");
2636 mDNS_Close(&mDNSStorage
);
2639 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2642 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2646 // uds_daemon.c support routines /////////////////////////////////////////////
2648 // We keep a list of client-supplied event sources in PosixEventSource records
2649 struct CFSocketEventSource
2651 udsEventCallback Callback
;
2654 struct CFSocketEventSource
*Next
;
2656 CFRunLoopSourceRef RLS
;
2658 typedef struct CFSocketEventSource CFSocketEventSource
;
2660 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2662 mDNSlocal
void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
2663 // Called by CFSocket when data appears on socket
2669 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2670 source
->Callback(source
->Context
);
2673 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2674 // Arrange things so that callback is called with context when data appears on fd
2676 CFSocketEventSource
*newSource
;
2677 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2679 if (gEventSources
.LinkOffset
== 0)
2680 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2682 if (fd
>= FD_SETSIZE
|| fd
< 0)
2683 return mStatus_UnsupportedErr
;
2684 if (callback
== NULL
)
2685 return mStatus_BadParamErr
;
2687 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2688 if (NULL
== newSource
)
2689 return mStatus_NoMemoryErr
;
2691 newSource
->Callback
= callback
;
2692 newSource
->Context
= context
;
2695 cfContext
.info
= newSource
;
2696 if ( NULL
!= (newSource
->cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2697 cf_callback
, &cfContext
)) &&
2698 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0)))
2700 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2701 AddToTail(&gEventSources
, newSource
);
2707 CFSocketInvalidate(newSource
->cfs
); // Note: Also closes the underlying socket
2708 CFRelease(newSource
->cfs
);
2710 return mStatus_NoMemoryErr
;
2713 return mStatus_NoError
;
2716 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2717 // Reverse what was done in udsSupportAddFDToEventLoop().
2719 CFSocketEventSource
*iSource
;
2721 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2723 if (fd
== iSource
->fd
)
2725 RemoveFromList(&gEventSources
, iSource
);
2726 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2727 CFRunLoopSourceInvalidate(iSource
->RLS
);
2728 CFRelease(iSource
->RLS
);
2729 CFSocketInvalidate(iSource
->cfs
); // Note: Also closes the underlying socket
2730 CFRelease(iSource
->cfs
);
2732 return mStatus_NoError
;
2735 return mStatus_NoSuchNameErr
;
2738 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2739 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2740 asm(".desc ___crashreporter_info__, 0x10");
2742 // For convenience when using the "strings" command, this is the last thing in the file
2743 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";