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 2005/03/09 00:48:43 cheshire
40 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
41 Move "m->p->NetworkChanged = 0;" line from caller to callee
43 Revision 1.254 2005/03/03 04:34:19 cheshire
44 <rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
46 Revision 1.253 2005/03/03 03:55:09 cheshire
47 <rdar://problem/3862944> Name collision notifications should be localized
49 Revision 1.252 2005/02/23 02:29:17 cheshire
50 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
51 Minor refinements, better variable names, improved comments
53 Revision 1.251 2005/02/21 21:31:24 ksekar
54 <rdar://problem/4015162> changed LogMsg to debugf
56 Revision 1.250 2005/02/19 01:25:04 cheshire
57 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
60 Revision 1.249 2005/02/19 00:28:45 cheshire
61 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
63 Revision 1.248 2005/02/19 00:18:34 cheshire
64 Confusing variable name -- alertMessage should be called alertHeader
66 Revision 1.247 2005/02/15 02:13:49 cheshire
67 If we did registerBootstrapService() when starting, then we must do
68 destroyBootstrapService() before exiting, or Mach init will keep restarting us.
70 Revision 1.246 2005/02/03 00:44:37 cheshire
71 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
73 Revision 1.245 2005/02/01 19:56:47 ksekar
74 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
76 Revision 1.244 2005/01/28 00:34:49 cheshire
77 Turn off "Starting time value" log message
79 Revision 1.243 2005/01/27 17:46:58 cheshire
80 Added comment about CFSocketInvalidate closing the underlying socket
82 Revision 1.242 2005/01/27 00:10:58 cheshire
83 <rdar://problem/3967867> Name change log messages every time machine boots
85 Revision 1.241 2005/01/25 17:28:06 ksekar
86 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
88 Revision 1.240 2005/01/21 02:39:18 cheshire
89 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
91 Revision 1.239 2005/01/20 00:25:01 cheshire
92 Improve validatelists() log message generation
94 Revision 1.238 2005/01/19 19:15:35 ksekar
95 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
97 Revision 1.237 2005/01/19 03:33:09 cheshire
98 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
100 Revision 1.236 2005/01/19 03:16:38 cheshire
101 <rdar://problem/3961051> CPU Spin in mDNSResponder
102 Improve detail of "Task Scheduling Error" diagnostic messages
104 Revision 1.235 2005/01/15 00:56:41 ksekar
105 <rdar://problem/3954575> Unicast services don't disappear when logging
108 Revision 1.234 2005/01/10 03:42:30 ksekar
111 Revision 1.233 2004/12/18 00:53:46 cheshire
112 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
114 Revision 1.232 2004/12/17 23:37:48 cheshire
115 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
116 (and other repetitive configuration changes)
118 Revision 1.231 2004/12/17 04:13:38 cheshire
119 Removed debugging check
121 Revision 1.230 2004/12/17 04:09:30 cheshire
122 <rdar://problem/3191011> Switch mDNSResponder to launchd
124 Revision 1.229 2004/12/16 21:51:36 cheshire
125 Remove some startup messages
127 Revision 1.228 2004/12/16 20:13:01 cheshire
128 <rdar://problem/3324626> Cache memory management improvements
130 Revision 1.227 2004/12/10 13:52:57 cheshire
131 <rdar://problem/3909995> Turn off SIGPIPE signals
133 Revision 1.226 2004/12/10 05:27:26 cheshire
134 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
136 Revision 1.225 2004/12/10 04:28:29 cheshire
137 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
139 Revision 1.224 2004/12/10 00:41:05 cheshire
140 Adjust alignment of log messages
142 Revision 1.223 2004/12/07 20:42:34 cheshire
143 Add explicit context parameter to mDNS_RemoveRecordFromService()
145 Revision 1.222 2004/12/06 21:15:23 ksekar
146 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
148 Revision 1.221 2004/11/30 03:24:04 cheshire
149 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
151 Revision 1.220 2004/11/29 23:34:31 cheshire
152 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
153 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
154 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
156 Revision 1.219 2004/11/25 01:00:56 cheshire
157 Checkin 1.217 not necessary
159 Revision 1.218 2004/11/24 20:27:19 cheshire
160 Add missing "err" parameter in LogMsg() call
162 Revision 1.217 2004/11/24 17:55:01 ksekar
163 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
165 Revision 1.216 2004/11/24 00:10:44 cheshire
166 <rdar://problem/3869241> For unicast operations, verify that service types are legal
168 Revision 1.215 2004/11/23 22:33:01 cheshire
169 <rdar://problem/3654910> Remove temporary workaround code for iChat
171 Revision 1.214 2004/11/23 22:13:59 cheshire
172 <rdar://problem/3886293> Subtype advertising broken for Mach API
174 Revision 1.213 2004/11/23 06:12:55 cheshire
175 <rdar://problem/3871405> Update wording for name conflict dialogs
177 Revision 1.212 2004/11/23 05:15:37 cheshire
178 <rdar://problem/3875830> Computer Name in use message garbled
180 Revision 1.211 2004/11/23 05:00:41 cheshire
181 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
183 Revision 1.210 2004/11/03 03:45:17 cheshire
184 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
186 Revision 1.209 2004/11/03 02:25:50 cheshire
187 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
189 Revision 1.208 2004/11/03 01:54:14 cheshire
190 Update debugging messages
192 Revision 1.207 2004/11/02 23:58:19 cheshire
193 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
195 Revision 1.206 2004/10/28 02:40:47 cheshire
196 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
198 Revision 1.205 2004/10/28 02:21:01 cheshire
199 <rdar://problem/3856500> Improve mDNSResponder signal handling
200 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
201 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
203 Revision 1.204 2004/10/27 01:57:21 cheshire
204 Add check of m->p->InterfaceList
206 Revision 1.203 2004/10/26 04:31:44 cheshire
207 Rename CountSubTypes() as ChopSubTypes()
209 Revision 1.202 2004/10/26 01:29:18 cheshire
210 Use "#if 0" instead of commenting out code
212 Revision 1.201 2004/10/25 21:41:39 ksekar
213 <rdar://problem/3852958> wide-area name conflicts can cause crash
215 Revision 1.200 2004/10/22 01:03:55 cheshire
216 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
217 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
219 Revision 1.199 2004/10/19 21:33:19 cheshire
220 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
221 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
222 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
224 Revision 1.198 2004/10/15 23:00:18 ksekar
225 <rdar://problem/3799242> Need to update LLQs on location changes
227 Revision 1.197 2004/10/12 23:38:59 ksekar
228 <rdar://problem/3837065> remove unnecessary log message
230 Revision 1.196 2004/10/04 05:56:04 cheshire
231 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
233 Revision 1.195 2004/09/30 00:24:59 ksekar
234 <rdar://problem/3695802> Dynamically update default registration domains on config change
236 Revision 1.194 2004/09/26 23:20:35 ksekar
237 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
239 Revision 1.193 2004/09/23 23:35:27 cheshire
242 Revision 1.192 2004/09/21 23:40:12 ksekar
243 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
245 Revision 1.191 2004/09/21 21:05:12 cheshire
246 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
247 into mDNSShared/uds_daemon.c
249 Revision 1.190 2004/09/21 19:51:15 cheshire
250 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
252 Revision 1.189 2004/09/21 18:17:23 cheshire
253 <rdar://problem/3785400> Add version info to mDNSResponder
255 Revision 1.188 2004/09/20 21:45:27 ksekar
258 Revision 1.187 2004/09/17 01:08:52 cheshire
259 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
260 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
261 declared in that file are ONLY appropriate to single-address-space embedded applications.
262 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
264 Revision 1.186 2004/09/16 00:24:49 cheshire
265 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
267 Revision 1.185 2004/08/25 02:01:45 cheshire
268 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
270 Revision 1.184 2004/08/19 19:04:12 ksekar
271 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
273 Revision 1.183 2004/08/14 03:22:42 cheshire
274 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
275 Add GetUserSpecifiedDDNSName() routine
276 Convert ServiceRegDomain to domainname instead of C string
277 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
279 Revision 1.182 2004/08/13 23:57:59 cheshire
280 Get rid of non-portable "_UNUSED"
282 Revision 1.181 2004/08/11 02:02:26 cheshire
283 Remove "mDNS *globalInstance" parameter from udsserver_init();
284 Move CheckForDuplicateRegistrations to uds_daemon.c
286 Revision 1.180 2004/07/13 21:24:25 rpantos
287 Fix for <rdar://problem/3701120>.
289 Revision 1.179 2004/06/19 00:02:54 cheshire
290 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
292 Revision 1.178 2004/06/18 19:10:00 cheshire
293 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
295 Revision 1.177 2004/06/16 23:14:46 ksekar
296 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
298 Revision 1.176 2004/06/11 20:27:42 cheshire
299 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
301 Revision 1.175 2004/06/10 20:23:21 cheshire
302 Also list interfaces in SIGINFO output
304 Revision 1.174 2004/06/08 18:54:48 ksekar
305 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
307 Revision 1.173 2004/06/08 17:35:12 cheshire
308 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
310 Revision 1.172 2004/06/05 00:04:26 cheshire
311 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
313 Revision 1.171 2004/06/04 08:58:30 ksekar
314 <rdar://problem/3668624>: Keychain integration for secure dynamic update
316 Revision 1.170 2004/05/30 20:01:50 ksekar
317 <rdar://problem/3668635>: wide-area default registrations should be in
318 .local too - fixed service registration when clients pass an explicit
319 domain (broken by previous checkin)
321 Revision 1.169 2004/05/30 01:30:16 ksekar
322 <rdar://problem/3668635>: wide-area default registrations should be in
325 Revision 1.168 2004/05/18 23:51:26 cheshire
326 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
328 Revision 1.167 2004/05/14 16:39:47 ksekar
329 Browse for iChat locally for now.
331 Revision 1.166 2004/05/13 21:33:52 ksekar
332 Clean up non-local registration control via config file. Force iChat
333 registrations to be local for now.
335 Revision 1.165 2004/05/13 04:54:20 ksekar
336 Unified list copy/free code. Added symetric list for
338 Revision 1.164 2004/05/12 22:03:08 ksekar
339 Made GetSearchDomainList a true platform-layer call (declaration moved
340 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
341 only on non-OSX platforms. Changed call to return a copy of the list
342 to avoid shared memory issues. Added a routine to free the list.
344 Revision 1.163 2004/05/12 02:03:25 ksekar
345 Non-local domains will only be browsed by default, and show up in
346 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
348 Revision 1.162 2004/04/14 23:09:29 ksekar
349 Support for TSIG signed dynamic updates.
351 Revision 1.161 2004/04/07 01:20:04 cheshire
352 Hash slot value should be unsigned
354 Revision 1.160 2004/04/06 19:51:24 cheshire
355 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
356 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
358 Revision 1.159 2004/04/03 01:36:55 cheshire
359 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
360 If "nobody" user doesn't exist, log a message and continue as "root"
362 Revision 1.158 2004/04/02 21:39:05 cheshire
363 Fix errors in comments
365 Revision 1.157 2004/03/19 18:49:10 ksekar
366 Increased size check in freeL() to account for LargeCacheRecord
367 structs larger than 8k
369 Revision 1.156 2004/03/19 18:19:19 ksekar
370 Fixed daemon.c to compile with malloc debugging turned on.
372 Revision 1.155 2004/03/13 01:57:34 ksekar
373 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
375 Revision 1.154 2004/03/12 08:42:47 cheshire
376 <rdar://problem/3548256>: Should not allow empty string for resolve domain
378 Revision 1.153 2004/03/12 08:08:51 cheshire
381 Revision 1.152 2004/02/05 19:39:29 cheshire
382 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
383 so that all platforms get this functionality
385 Revision 1.151 2004/02/03 22:35:34 cheshire
386 <rdar://problem/3548256>: Should not allow empty string for resolve domain
388 Revision 1.150 2004/01/28 21:14:23 cheshire
389 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
391 Revision 1.149 2004/01/28 02:30:08 ksekar
392 Added default Search Domains to unicast browsing, controlled via
393 Networking sharing prefs pane. Stopped sending unicast messages on
394 every interface. Fixed unicast resolving via mach-port API.
396 Revision 1.148 2004/01/25 00:03:20 cheshire
397 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
399 Revision 1.147 2004/01/19 19:51:46 cheshire
400 Fix compiler error (mixed declarations and code) on some versions of Linux
402 Revision 1.146 2003/12/08 21:00:46 rpantos
403 Changes to support mDNSResponder on Linux.
405 Revision 1.145 2003/12/05 22:08:07 cheshire
406 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
408 Revision 1.144 2003/11/19 23:21:08 ksekar
409 <rdar://problem/3486646>: config change handler not called for dns-sd services
411 Revision 1.143 2003/11/14 21:18:32 cheshire
412 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
413 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
415 Revision 1.142 2003/11/08 22:18:29 cheshire
416 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
418 Revision 1.141 2003/11/07 02:30:57 cheshire
419 Also check per-slot cache use counts in SIGINFO state log
421 Revision 1.140 2003/10/21 19:58:26 cheshire
422 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
424 Revision 1.139 2003/10/21 00:10:18 rpantos
425 <rdar://problem/3409401>: mDNSResponder should not run as root
427 Revision 1.138 2003/10/07 20:16:58 cheshire
428 Shorten syslog message a bit
430 Revision 1.137 2003/09/23 02:12:43 cheshire
431 Also include port number in list of services registered via new UDS API
433 Revision 1.136 2003/09/23 02:07:25 cheshire
434 Include port number in DNSServiceRegistration START/STOP messages
436 Revision 1.135 2003/09/23 01:34:02 cheshire
437 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
439 Revision 1.134 2003/08/21 20:01:37 cheshire
440 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
442 Revision 1.133 2003/08/20 23:39:31 cheshire
443 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
445 Revision 1.132 2003/08/20 01:44:56 cheshire
446 Fix errors in LogOperation() calls (only used for debugging)
448 Revision 1.131 2003/08/19 05:39:43 cheshire
449 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
451 Revision 1.130 2003/08/16 03:39:01 cheshire
452 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
454 Revision 1.129 2003/08/15 20:16:03 cheshire
455 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
456 We want to avoid touching the rdata pages, so we don't page them in.
457 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
458 Moved this from the RData to the ResourceRecord object.
459 2. To avoid unnecessarily touching the rdata just to compare it,
460 compute a hash of the rdata and store the hash in the ResourceRecord object.
462 Revision 1.128 2003/08/14 19:30:36 cheshire
463 <rdar://problem/3378473> Include list of cache records in SIGINFO output
465 Revision 1.127 2003/08/14 02:18:21 cheshire
466 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
468 Revision 1.126 2003/08/12 19:56:25 cheshire
471 Revision 1.125 2003/08/08 18:36:04 cheshire
472 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
474 Revision 1.124 2003/07/25 18:28:23 cheshire
475 Minor fix to error messages in syslog: Display string parameters with quotes
477 Revision 1.123 2003/07/23 17:45:28 cheshire
478 <rdar://problem/3339388> mDNSResponder leaks a bit
479 Don't allocate memory for the reply until after we've verified that the reply is valid
481 Revision 1.122 2003/07/23 00:00:04 cheshire
484 Revision 1.121 2003/07/20 03:38:51 ksekar
485 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
487 Revision 1.120 2003/07/18 00:30:00 cheshire
488 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
490 Revision 1.119 2003/07/17 19:08:58 cheshire
491 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
493 Revision 1.118 2003/07/15 21:12:28 cheshire
494 Added extra debugging checks in validatelists() (not used in final shipping version)
496 Revision 1.117 2003/07/15 01:55:15 cheshire
497 <rdar://problem/3315777> Need to implement service registration with subtypes
499 Revision 1.116 2003/07/02 21:19:51 cheshire
500 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
502 Revision 1.115 2003/07/02 02:41:24 cheshire
503 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
505 Revision 1.114 2003/07/01 21:10:20 cheshire
506 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
508 Revision 1.113 2003/06/28 17:27:43 vlubet
509 <rdar://problem/3221246> Redirect standard input, standard output, and
510 standard error file descriptors to /dev/null just like any other
513 Revision 1.112 2003/06/25 23:42:19 ksekar
514 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
515 Reviewed by: Stuart Cheshire
516 Added files necessary to implement Unix domain sockets based enhanced
517 DNS-SD APIs, and integrated with existing Mach-port based daemon.
519 Revision 1.111 2003/06/11 01:02:43 cheshire
520 <rdar://problem/3287858> mDNSResponder binary compatibility
521 Make single binary that can run on both Jaguar and Panther.
523 Revision 1.110 2003/06/10 01:14:11 cheshire
524 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
526 Revision 1.109 2003/06/06 19:53:43 cheshire
527 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
528 (Global search-and-replace; no functional change to code execution.)
530 Revision 1.108 2003/06/06 14:08:06 cheshire
531 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
533 Revision 1.107 2003/05/29 05:44:55 cheshire
534 Minor fixes to log messages
536 Revision 1.106 2003/05/27 18:30:55 cheshire
537 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
538 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
540 Revision 1.105 2003/05/26 03:21:29 cheshire
541 Tidy up address structure naming:
542 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
543 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
544 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
546 Revision 1.104 2003/05/26 00:42:06 cheshire
547 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
549 Revision 1.103 2003/05/23 23:07:44 cheshire
550 <rdar://problem/3268199> Must not write to stderr when running as daemon
552 Revision 1.102 2003/05/22 01:32:31 cheshire
553 Fix typo in Log message format string
555 Revision 1.101 2003/05/22 00:26:55 cheshire
556 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
557 Modify error message to explain that this is technically legal, but may indicate a bug.
559 Revision 1.100 2003/05/21 21:02:24 ksekar
560 <rdar://problem/3247035>: Service should be prefixed
561 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
562 Mach message port to "com.apple.mDNSResponder.
564 Revision 1.99 2003/05/21 17:33:49 cheshire
565 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
567 Revision 1.98 2003/05/20 00:33:07 cheshire
568 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
569 SIGHUP now writes state summary to syslog
571 Revision 1.97 2003/05/08 00:19:08 cheshire
572 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
574 Revision 1.96 2003/05/07 22:10:46 cheshire
575 <rdar://problem/3250330> Add a few more error logging messages
577 Revision 1.95 2003/05/07 19:20:17 cheshire
578 <rdar://problem/3251391> Add version number to mDNSResponder builds
580 Revision 1.94 2003/05/07 00:28:18 cheshire
581 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
583 Revision 1.93 2003/05/06 00:00:49 cheshire
584 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
586 Revision 1.92 2003/04/04 20:38:57 cheshire
591 #include <mach/mach.h>
592 #include <mach/mach_error.h>
593 #include <servers/bootstrap.h>
594 #include <sys/types.h>
599 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
601 #include "DNSServiceDiscoveryRequestServer.h"
602 #include "DNSServiceDiscoveryReply.h"
604 #include "DNSCommon.h"
605 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
607 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
609 #include "GenLinkedList.h"
611 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
613 //*************************************************************************************************************
616 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
617 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
618 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
619 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
620 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
622 //*************************************************************************************************************
625 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
626 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
627 static mDNS_PlatformSupport PlatformStorage
;
629 // Start off with a default cache of 16K (about 100 records)
630 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
631 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
633 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
634 static mach_port_t client_death_port
= MACH_PORT_NULL
;
635 static mach_port_t signal_port
= MACH_PORT_NULL
;
636 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
638 // mDNS Mach Message Timeout, in milliseconds.
639 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
640 // fails to service its mach message queue, but long enough to give a well-written
641 // client a chance to service its mach message queue without getting cut off.
642 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
643 // even extra-slow clients a fair chance before we cut them off.
644 #define MDNS_MM_TIMEOUT 250
646 static int restarting_via_mach_init
= 0;
647 static int started_via_launchdaemon
= 0;
651 //*************************************************************************************************************
652 // Active client list structures
654 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
655 struct DNSServiceDomainEnumeration_struct
657 DNSServiceDomainEnumeration
*next
;
658 mach_port_t ClientMachPort
;
659 DNSQuestion dom
; // Question asking for domains
660 DNSQuestion def
; // Question asking for default domain
663 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
664 struct DNSServiceBrowserResult_struct
666 DNSServiceBrowserResult
*next
;
671 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
673 typedef struct DNSServiceBrowserQuestion
675 struct DNSServiceBrowserQuestion
*next
;
678 } DNSServiceBrowserQuestion
;
680 struct DNSServiceBrowser_struct
682 DNSServiceBrowser
*next
;
683 mach_port_t ClientMachPort
;
684 DNSServiceBrowserQuestion
*qlist
;
685 DNSServiceBrowserResult
*results
;
687 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
688 domainname type
; // registration type
691 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
692 struct DNSServiceResolver_struct
694 DNSServiceResolver
*next
;
695 mach_port_t ClientMachPort
;
701 // A single registered service: ServiceRecordSet + bookkeeping
702 // Note that we duplicate some fields from parent DNSServiceRegistration object
703 // to facilitate cleanup, when instances and parent may be deallocated at different times.
704 typedef struct ServiceInstance
706 struct ServiceInstance
*next
;
707 mach_port_t ClientMachPort
;
708 mDNSBool autoname
; // Set if this name is tied to the Computer Name
709 mDNSBool autorename
; // Set if we just got a name conflict and now need to automatically pick a new name
712 ServiceRecordSet srs
;
713 // Don't add any fields after ServiceRecordSet.
714 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
717 // A client-created service. May reference several ServiceInstance objects if default
718 // settings cause registration in multiple domains.
719 typedef struct DNSServiceRegistration
721 struct DNSServiceRegistration
*next
;
722 mach_port_t ClientMachPort
;
723 mDNSBool DefaultDomain
;
727 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
728 domainlabel name
; // used only if autoname is false
731 unsigned char txtinfo
[1024];
734 ServiceInstance
*regs
;
735 } DNSServiceRegistration
;
737 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
738 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
739 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
740 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
742 //*************************************************************************************************************
743 // General Utility Functions
745 #if MACOSX_MDNS_MALLOC_DEBUGGING
747 char _malloc_options
[] = "AXZ";
749 mDNSlocal
void validatelists(mDNS
*const m
)
751 DNSServiceDomainEnumeration
*e
;
752 DNSServiceBrowser
*b
;
753 DNSServiceResolver
*l
;
754 DNSServiceRegistration
*r
;
760 NetworkInterfaceInfoOSX
*i
;
762 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
763 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
764 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
);
766 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
767 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
768 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
);
770 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
771 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
772 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
);
774 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
775 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
776 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
);
778 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
780 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
781 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
782 if (rr
->resrec
.name
!= &rr
->namestorage
)
783 LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
784 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
787 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
788 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
789 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
791 for (q
= m
->Questions
; q
; q
=q
->next
)
792 if (q
->ThisQInterval
== (mDNSs32
)~0)
793 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
);
795 FORALL_CACHERECORDS(slot
, cg
, cr
)
796 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
797 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->resrec
.RecordType
);
799 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
801 LogMsg("!!!! InterfaceList: %p is garbage !!!!", i
);
804 void *mallocL(char *msg
, unsigned int size
)
806 unsigned long *mem
= malloc(size
+8);
809 LogMsg("malloc( %s : %d ) failed", msg
, size
);
814 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
817 //bzero(&mem[2], size);
818 memset(&mem
[2], 0xFF, size
);
819 validatelists(&mDNSStorage
);
824 void freeL(char *msg
, void *x
)
827 LogMsg("free( %s @ NULL )!", msg
);
830 unsigned long *mem
= ((unsigned long *)x
) - 2;
831 if (mem
[0] != 0xDEAD1234)
832 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
834 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
835 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
836 //bzero(mem, mem[1]+8);
837 memset(mem
, 0xFF, mem
[1]+8);
838 validatelists(&mDNSStorage
);
845 //*************************************************************************************************************
846 // Client Death Detection
848 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
850 ServiceRecordSet
*s
= &x
->srs
;
851 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
855 e
->r
.RecordContext
= e
;
858 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
861 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
862 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
864 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
865 freeL("ServiceInstance", x
);
868 // AbortClient finds whatever client is identified by the given Mach port,
869 // stops whatever operation that client was doing, and frees its memory.
870 // In the case of a service registration, the actual freeing may be deferred
871 // until we get the mStatus_MemFree message, if necessary
872 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
874 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
875 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
876 DNSServiceResolver
**l
= &DNSServiceResolverList
;
877 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
879 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
882 DNSServiceDomainEnumeration
*x
= *e
;
885 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
886 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
887 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
888 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
889 freeL("DNSServiceDomainEnumeration", x
);
893 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
896 DNSServiceBrowser
*x
= *b
;
897 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
902 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
903 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
904 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
907 freeL("DNSServiceBrowserQuestion", freePtr
);
911 DNSServiceBrowserResult
*r
= x
->results
;
912 x
->results
= x
->results
->next
;
913 freeL("DNSServiceBrowserResult", r
);
915 freeL("DNSServiceBrowser", x
);
919 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
922 DNSServiceResolver
*x
= *l
;
925 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
926 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
927 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
928 freeL("DNSServiceResolver", x
);
932 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
935 ServiceInstance
*si
= NULL
;
936 DNSServiceRegistration
*x
= *r
;
942 ServiceInstance
*instance
= si
;
944 instance
->autorename
= mDNSfalse
;
945 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
);
946 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
948 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
949 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
950 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
951 // the list, so we should go ahead and free the memory right now
952 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
955 freeL("DNSServiceRegistration", x
);
959 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
962 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
964 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
966 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
967 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
968 DNSServiceResolver
*l
= DNSServiceResolverList
;
969 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
970 DNSServiceBrowserQuestion
*qptr
;
972 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
973 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
974 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
975 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
976 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
979 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
980 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
982 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
986 for (si
= r
->regs
; si
; si
= si
->next
) LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
988 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
993 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
995 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
996 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
997 DNSServiceResolver
*l
= DNSServiceResolverList
;
998 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
999 DNSServiceBrowserQuestion
*qptr
;
1001 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1002 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1003 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1004 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1005 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
1008 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1009 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
1011 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
1012 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
1013 return(e
|| b
|| l
|| r
);
1016 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
1018 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
1019 (void)unusedport
; // Unused
1020 (void)size
; // Unused
1021 (void)info
; // Unused
1022 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1024 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
1025 AbortClient(deathMessage
->not_port
, NULL
);
1027 /* Deallocate the send right that came in the dead name notification */
1028 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
1032 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
1035 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
1036 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
1037 // If the port already died while we were thinking about it, then abort the operation right away
1038 if (r
!= KERN_SUCCESS
)
1039 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1042 //*************************************************************************************************************
1043 // Domain Enumeration
1045 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1047 kern_return_t status
;
1049 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1050 DNSServiceDomainEnumerationReplyResultType rt
;
1051 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1053 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1054 if (answer
->rrtype
!= kDNSType_PTR
) return;
1055 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1059 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1060 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1064 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1068 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1069 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1070 !AddRecord
? "RemoveDomain" :
1071 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1073 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1074 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1075 if (status
== MACH_SEND_TIMED_OUT
)
1076 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1079 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1082 // Check client parameter
1083 (void)unusedserver
; // Unused
1084 mStatus err
= mStatus_NoError
;
1085 const char *errormsg
= "Unknown";
1086 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1087 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1089 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1090 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1092 // Allocate memory, and handle failure
1093 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1094 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1096 // Set up object, and link into list
1097 x
->ClientMachPort
= client
;
1098 x
->next
= DNSServiceDomainEnumerationList
;
1099 DNSServiceDomainEnumerationList
= x
;
1101 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1104 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1105 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1106 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1108 // Succeeded: Wrap up and return
1109 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1110 EnableDeathNotificationForClient(client
, x
);
1111 return(mStatus_NoError
);
1114 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
1118 //*************************************************************************************************************
1119 // Browse for services
1121 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1125 if (answer
->rrtype
!= kDNSType_PTR
)
1126 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1129 domainname type
, domain
;
1130 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1132 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1133 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1137 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1138 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1140 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1141 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1143 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1144 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1147 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1148 DNSServiceBrowserResult
**p
= &browser
->results
;
1149 while (*p
) p
= &(*p
)->next
;
1153 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1155 mStatus err
= mStatus_NoError
;
1156 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1158 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1160 if (SameDomainName(&ptr
->q
.qname
, d
))
1161 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1164 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1165 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1166 AssignDomainName(&question
->domain
, d
);
1167 question
->next
= browser
->qlist
;
1168 browser
->qlist
= question
;
1169 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1170 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1171 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1175 mDNSexport
void DefaultBrowseDomainChanged(const domainname
*d
, mDNSBool add
)
1177 DNSServiceBrowser
*ptr
;
1179 debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
1180 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1182 if (ptr
->DefaultDomain
)
1186 mStatus err
= AddDomainToBrowser(ptr
, d
);
1187 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1191 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1194 if (SameDomainName(&(*q
)->domain
, d
))
1196 DNSServiceBrowserQuestion
*remove
= *q
;
1198 if (remove
->q
.LongLived
)
1200 // give goodbyes for known answers. note that since events are sent to client via udns_execute(),
1201 // we don't need to worry about the question being cancelled mid-loop
1202 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
1203 while (ka
) { remove
->q
.QuestionCallback(&mDNSStorage
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
1205 mDNS_StopBrowse(&mDNSStorage
, &remove
->q
);
1206 freeL("DNSServiceBrowserQuestion", remove
);
1211 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1217 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1218 DNSCString regtype
, DNSCString domain
)
1220 // Check client parameter
1221 (void)unusedserver
; // Unused
1222 mStatus err
= mStatus_NoError
;
1223 const char *errormsg
= "Unknown";
1224 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
1226 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1227 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1229 // Check other parameters
1232 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1233 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1234 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1235 { errormsg
= "Bad Service SubType"; goto badparam
; }
1236 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1238 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1239 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1241 // Allocate memory, and handle failure
1242 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1243 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1245 // Set up object, and link into list
1246 AssignDomainName(&x
->type
, &t
);
1247 x
->ClientMachPort
= client
;
1251 x
->next
= DNSServiceBrowserList
;
1252 DNSServiceBrowserList
= x
;
1256 // Start browser for an explicit domain
1257 x
->DefaultDomain
= mDNSfalse
;
1258 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1259 err
= AddDomainToBrowser(x
, &d
);
1260 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1264 // Start browser on all domains
1265 x
->DefaultDomain
= mDNStrue
;
1266 SearchDomains
= mDNSPlatformGetSearchDomainList();
1267 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1268 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1270 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1273 // only terminally bail if .local fails
1274 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1275 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1276 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1281 // Succeeded: Wrap up and return
1282 EnableDeathNotificationForClient(client
, x
);
1283 mDNS_FreeDNameList(SearchDomains
);
1284 return(mStatus_NoError
);
1287 err
= mStatus_BadParamErr
;
1289 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1290 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
1294 //*************************************************************************************************************
1295 // Resolve Service Info
1297 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1299 kern_return_t status
;
1300 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1301 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1302 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1303 struct sockaddr_storage interface
;
1304 struct sockaddr_storage address
;
1306 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1309 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1311 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1313 bzero(&interface
, sizeof(interface
));
1314 bzero(&address
, sizeof(address
));
1316 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1318 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1319 sin
->sin_len
= sizeof(*sin
);
1320 sin
->sin_family
= AF_INET
;
1322 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1324 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1326 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1327 sin6
->sin6_len
= sizeof(*sin6
);
1328 sin6
->sin6_family
= AF_INET6
;
1329 sin6
->sin6_flowinfo
= 0;
1330 sin6
->sin6_port
= 0;
1331 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1332 sin6
->sin6_scope_id
= ifx
->scope_id
;
1335 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1337 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1338 sin
->sin_len
= sizeof(*sin
);
1339 sin
->sin_family
= AF_INET
;
1340 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1341 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1345 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1346 sin6
->sin6_len
= sizeof(*sin6
);
1347 sin6
->sin6_family
= AF_INET6
;
1348 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1349 sin6
->sin6_flowinfo
= 0;
1350 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1351 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1354 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1355 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1356 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1357 // ASCII-1 characters are used in the C-string as boundary markers,
1358 // to indicate the boundaries between the original constituent P-strings.
1359 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1362 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1366 pstrlen
= query
->info
->TXTinfo
[i
];
1369 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1371 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1372 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1373 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1374 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1375 if (status
== MACH_SEND_TIMED_OUT
)
1376 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1379 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1380 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1382 // Check client parameter
1383 (void)unusedserver
; // Unused
1384 mStatus err
= mStatus_NoError
;
1385 const char *errormsg
= "Unknown";
1386 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1387 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1389 // Check other parameters
1391 domainname t
, d
, srv
;
1392 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1393 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1394 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1395 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1397 // Allocate memory, and handle failure
1398 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1399 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1401 // Set up object, and link into list
1402 x
->ClientMachPort
= client
;
1403 x
->i
.InterfaceID
= mDNSInterface_Any
;
1405 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1406 x
->next
= DNSServiceResolverList
;
1407 DNSServiceResolverList
= x
;
1410 LogOperation("%5d: DNSServiceResolver(%##s) START", client
, x
->i
.name
.c
);
1411 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1412 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1414 // Succeeded: Wrap up and return
1415 EnableDeathNotificationForClient(client
, x
);
1416 return(mStatus_NoError
);
1419 err
= mStatus_BadParamErr
;
1421 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1425 //*************************************************************************************************************
1428 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1430 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1433 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1435 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1437 if (result
== mStatus_NoError
)
1439 kern_return_t status
;
1440 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1441 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1442 if (status
== MACH_SEND_TIMED_OUT
)
1443 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1444 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1445 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1448 else if (result
== mStatus_NameConflict
)
1450 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1451 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1452 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1453 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1455 // On conflict for an autoname service, rename and reregister *all* autoname services
1456 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1457 m
->MainCallback(m
, mStatus_ConfigChanged
);
1459 else if (si
->autoname
)
1461 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1466 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1467 // of their registration in the usual way (which we will catch via client death notification).
1468 // If the Mach queue is full, we forcibly abort the client immediately.
1469 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1470 if (status
== MACH_SEND_TIMED_OUT
)
1471 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1475 else if (result
== mStatus_MemFree
)
1479 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1480 si
->autorename
= mDNSfalse
;
1481 si
->name
= m
->nicelabel
;
1482 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1486 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1487 DNSServiceRegistration
*r
;
1488 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1490 ServiceInstance
*sp
= r
->regs
, *prev
= NULL
;
1495 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
->c
);
1496 if (prev
) prev
->next
= sp
->next
;
1497 else r
->regs
= sp
->next
;
1505 FreeServiceInstance(si
);
1509 else if (result
!= mStatus_NATTraversal
)
1510 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1513 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1516 ServiceInstance
*si
= NULL
;
1517 AuthRecord
*SubTypes
= NULL
;
1519 for (si
= x
->regs
; si
; si
= si
->next
)
1521 if (SameDomainName(&si
->domain
, domain
))
1522 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1525 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1526 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1528 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1529 if (!si
) return mStatus_NoMemoryErr
;
1531 si
->ClientMachPort
= x
->ClientMachPort
;
1532 si
->autorename
= mDNSfalse
;
1533 si
->autoname
= x
->autoname
;
1534 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1535 si
->domain
= *domain
;
1537 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
);
1545 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1546 freeL("ServiceInstance", si
);
1551 mDNSexport
void DefaultRegDomainChanged(const domainname
*d
, mDNSBool add
)
1553 DNSServiceRegistration
*reg
;
1555 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1557 if (reg
->DefaultDomain
)
1561 AddServiceInstance(reg
, d
);
1565 ServiceInstance
*si
= reg
->regs
, *prev
= NULL
;
1568 if (SameDomainName(&si
->domain
, d
))
1570 if (prev
) prev
->next
= si
->next
;
1571 else reg
->regs
= si
->next
;
1572 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
))
1573 FreeServiceInstance(si
); // only free memory synchronously on error
1579 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1585 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1586 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1588 (void)unusedserver
; // Unused
1589 mStatus err
= mStatus_NoError
;
1590 const char *errormsg
= "Unknown";
1592 // older versions of this code passed the port via mach IPC as an int.
1593 // we continue to pass it as 4 bytes to maintain binary compatibility,
1594 // but now ensure that the network byte order is preserved by using a struct
1596 port
.b
[0] = IpPort
.bytes
[2];
1597 port
.b
[1] = IpPort
.bytes
[3];
1599 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1600 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1602 // Check for sub-types after the service type
1603 size_t reglen
= strlen(regtype
) + 1;
1604 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1605 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1606 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1608 // Check other parameters
1612 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1613 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1614 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1615 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1616 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1618 unsigned char txtinfo
[1024] = "";
1619 unsigned int data_len
= 0;
1620 unsigned int size
= sizeof(RDataBody
);
1621 unsigned char *pstring
= &txtinfo
[data_len
];
1622 char *ptr
= txtRecord
;
1624 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1625 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1626 // Hence we have to convert the C-string to a P-string.
1627 // ASCII-1 characters are allowed in the C-string as boundary markers,
1628 // so that a single C-string can be used to represent one or more P-strings.
1631 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1632 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1634 pstring
= &txtinfo
[data_len
];
1640 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1641 pstring
[++pstring
[0]] = *ptr
++;
1646 if (size
< data_len
)
1649 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1650 // a port number of zero. When two instances of the protected client are allowed to run on one
1651 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1652 if (port
.NotAnInteger
)
1654 int count
= CountExistingRegistrations(&srv
, port
);
1656 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1657 client
, count
+1, srv
.c
, mDNSVal16(port
));
1660 // Allocate memory, and handle failure
1661 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1662 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1663 bzero(x
, sizeof(*x
));
1665 // Set up object, and link into list
1666 x
->ClientMachPort
= client
;
1667 x
->DefaultDomain
= !domain
[0];
1668 x
->autoname
= (!name
[0]);
1670 x
->NumSubTypes
= NumSubTypes
;
1671 memcpy(x
->regtype
, regtype
, reglen
);
1675 memcpy(x
->txtinfo
, txtinfo
, 1024);
1676 x
->txt_len
= data_len
;
1680 x
->next
= DNSServiceRegistrationList
;
1681 DNSServiceRegistrationList
= x
;
1683 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1684 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1686 err
= AddServiceInstance(x
, &d
);
1687 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1689 if (x
->DefaultDomain
)
1691 DNameListElem
*ptr
, *regdomains
= mDNSPlatformGetRegDomainList();
1692 for (ptr
= regdomains
; ptr
; ptr
= ptr
->next
)
1693 AddServiceInstance(x
, &ptr
->name
);
1694 mDNS_FreeDNameList(regdomains
);
1697 // Succeeded: Wrap up and return
1698 EnableDeathNotificationForClient(client
, x
);
1699 return(mStatus_NoError
);
1702 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1704 err
= mStatus_BadParamErr
;
1706 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1707 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1711 mDNSlocal CFUserNotificationRef gNotification
= NULL
;
1712 mDNSlocal CFRunLoopSourceRef gNotificationRLS
= NULL
;
1713 mDNSlocal domainlabel gNotificationPrefHostLabel
; // The prefs as they were the last time we saw them
1714 mDNSlocal domainlabel gNotificationPrefNiceLabel
;
1715 mDNSlocal domainlabel gNotificationUserHostLabel
; // The prefs as they were the last time the user changed them
1716 mDNSlocal domainlabel gNotificationUserNiceLabel
;
1718 mDNSlocal
void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
1720 (void)responseFlags
; // Unused
1721 if (userNotification
!= gNotification
) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
1722 if (gNotificationRLS
)
1724 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1725 CFRelease(gNotificationRLS
);
1726 gNotificationRLS
= NULL
;
1727 CFRelease(gNotification
);
1728 gNotification
= NULL
;
1730 // By dismissing the alert, the user has conceptually acknowleged the rename.
1731 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
1732 // If we get *another* conflict, the new alert should refer to the 'old'.
1733 // name as now being "computer-2.local", not "computer.local"
1734 gNotificationUserHostLabel
= gNotificationPrefHostLabel
;
1735 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
;
1738 mDNSlocal
void ShowNameConflictNotification(CFStringRef header
, CFStringRef subtext
)
1740 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1741 if (!dictionary
) return;
1742 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
1743 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
1745 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
1746 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
1748 if (gNotification
) // If notification already on-screen, update it in place
1749 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
1750 else // else, we need to create it
1753 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
1754 if (!gNotification
) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
1755 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
1756 if (!gNotificationRLS
) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
1757 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1760 CFRelease(dictionary
);
1763 // This updates either the text of the field currently labelled "Local Hostname",
1764 // or the text of the field currently labelled "Computer Name"
1765 // in the Sharing Prefs Control Panel
1766 mDNSlocal
void RecordUpdatedName(const mDNS
*const m
, const domainlabel
*const olddl
, const domainlabel
*const newdl
,
1767 const char *const msg
, const char *const suffix
, const CFStringRef subtext
)
1769 char oldname
[MAX_DOMAIN_LABEL
+1];
1770 char newname
[MAX_DOMAIN_LABEL
+1];
1771 ConvertDomainLabelToCString_unescaped(olddl
, oldname
);
1772 ConvertDomainLabelToCString_unescaped(newdl
, newname
);
1773 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
1774 const CFStringRef cfnewname
= CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
);
1775 const CFStringRef f1
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1776 const CFStringRef f2
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1777 const SCPreferencesRef session
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
);
1778 if (!cfoldname
|| !cfnewname
|| !f1
|| !f2
|| !session
|| !SCPreferencesLock(session
, 0)) // If we can't get the lock don't wait
1779 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1782 const CFStringRef s0
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1783 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
);
1784 const CFStringRef s2
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
);
1785 // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
1786 // element of the array individually for us, and then concatenate the results to make the final message.
1787 // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
1788 // On Panther this does not work, so we just build the string directly, and it will not be translated.
1789 const CFMutableStringRef alertHeader
=
1790 (OSXVers
< 8) ? CFStringCreateMutable(NULL
, 0) : (CFMutableStringRef
)CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1792 if (newdl
== &gNotificationPrefHostLabel
) result
= SCPreferencesSetLocalHostName(session
, cfnewname
);
1793 else result
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
);
1794 if (!result
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0
|| !s1
|| !s2
|| !alertHeader
)
1795 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1796 else if (m
->p
->NotifyUser
)
1800 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
1803 CFRelease(userName
);
1804 typedef void CFStringAppendFN(CFMutableStringRef theString
, CFStringRef appendedString
);
1805 CFStringAppendFN
*const append
= (OSXVers
< 8) ? &CFStringAppend
: (CFStringAppendFN
*)&CFArrayAppendValue
;
1806 append(alertHeader
, s0
);
1807 append(alertHeader
, s1
);
1808 append(alertHeader
, CFSTR("is already in use on this network."));
1809 append(alertHeader
, CFSTR(" "));
1810 append(alertHeader
, CFSTR("The name has been changed to"));
1811 append(alertHeader
, s2
);
1812 append(alertHeader
, CFSTR("automatically."));
1813 ShowNameConflictNotification(alertHeader
, subtext
);
1816 if (s0
) CFRelease(s0
);
1817 if (s1
) CFRelease(s1
);
1818 if (s2
) CFRelease(s2
);
1819 if (alertHeader
) CFRelease(alertHeader
);
1820 SCPreferencesUnlock(session
);
1822 if (cfoldname
) CFRelease(cfoldname
);
1823 if (cfnewname
) CFRelease(cfnewname
);
1824 if (f1
) CFRelease(f1
);
1825 if (f2
) CFRelease(f2
);
1826 if (session
) CFRelease(session
);
1829 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1832 if (result
== mStatus_NoError
)
1834 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1835 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1837 else if (result
== mStatus_ConfigChanged
)
1839 // If the user-specified hostlabel from System Configuration has changed since the last time
1840 // we saw it, and *we* didn't change it, then that implies that the user has changed it,
1841 // so we auto-dismiss the name conflict alert.
1842 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, gNotificationPrefHostLabel
.c
) ||
1843 !SameDomainLabel(m
->p
->usernicelabel
.c
, gNotificationPrefNiceLabel
.c
))
1845 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= m
->p
->userhostlabel
;
1846 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= m
->p
->usernicelabel
;
1847 // If we're showing a name conflict notification, and the user has manually edited
1848 // the name to remedy the conflict, we should now remove the notification window.
1849 if (gNotificationRLS
) CFUserNotificationCancel(gNotification
);
1852 DNSServiceRegistration
*r
;
1853 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1856 ServiceInstance
*si
;
1857 for (si
= r
->regs
; si
; si
= si
->next
)
1859 if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
))
1861 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1862 si
->autorename
= mDNStrue
;
1863 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1864 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1868 udsserver_handle_configchange();
1870 else if (result
== mStatus_GrowCache
)
1872 // Allocate another chunk of cache storage
1873 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1874 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1878 //*************************************************************************************************************
1879 // Add / Update / Remove records from existing Registration
1881 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1882 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1884 // Check client parameter
1886 mStatus err
= mStatus_NoError
;
1887 const char *errormsg
= "Unknown";
1888 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1889 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1890 ServiceInstance
*si
;
1892 (void)unusedserver
; // Unused
1893 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1894 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1896 // Check other parameters
1897 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1898 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1899 else size
= sizeof(RDataBody
);
1902 *reference
= (natural_t
)id
;
1903 for (si
= x
->regs
; si
; si
= si
->next
)
1905 // Allocate memory, and handle failure
1906 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1907 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1909 // Fill in type, length, and data of new record
1910 extra
->r
.resrec
.rrtype
= type
;
1911 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1912 extra
->r
.resrec
.rdlength
= data_len
;
1913 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1916 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1917 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1918 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1922 freeL("Extra Resource Record", extra
);
1923 errormsg
= "mDNS_AddRecordToService";
1927 extra
->ClientID
= id
;
1930 return mStatus_NoError
;
1933 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
1934 return mStatus_UnknownErr
;
1937 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1940 if (OldRData
!= &rr
->rdatastorage
)
1941 freeL("Old RData", OldRData
);
1944 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1946 // Check client parameter
1947 mStatus err
= mStatus_NoError
;
1948 const char *errormsg
= "Unknown";
1949 domainname
*name
= (domainname
*)"";
1951 name
= srs
->RR_SRV
.resrec
.name
;
1953 unsigned int size
= sizeof(RDataBody
);
1954 if (size
< data_len
)
1957 // Allocate memory, and handle failure
1958 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1959 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1961 // Fill in new length, and data
1962 newrdata
->MaxRDLength
= size
;
1963 memcpy(&newrdata
->u
, data
, data_len
);
1965 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
1966 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
1967 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
1968 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
1971 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1972 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1974 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1977 errormsg
= "mDNS_Update";
1978 freeL("RData", newrdata
);
1981 return(mStatus_NoError
);
1984 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1988 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1989 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1991 // Check client parameter
1992 mStatus err
= mStatus_NoError
;
1993 const char *errormsg
= "Unknown";
1994 domainname
*name
= (domainname
*)"";
1995 ServiceInstance
*si
;
1997 (void)unusedserver
; // unused
1998 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1999 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2000 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2001 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2003 // Check other parameters
2004 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
2006 for (si
= x
->regs
; si
; si
= si
->next
)
2008 AuthRecord
*r
= NULL
;
2010 // Find the record we're updating. NULL reference means update the primary TXT record
2011 if (!reference
) r
= &si
->srs
.RR_TXT
;
2014 ExtraResourceRecord
*ptr
;
2015 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2017 if ((natural_t
)ptr
->ClientID
== reference
)
2018 { r
= &ptr
->r
; break; }
2020 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
2022 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
2023 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
2026 return mStatus_NoError
;
2029 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
2033 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
2035 domainname
*name
= srs
->RR_SRV
.resrec
.name
;
2036 mStatus err
= mStatus_NoError
;
2039 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
2041 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
2042 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
2047 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2048 natural_t reference
)
2050 // Check client parameter
2051 (void)unusedserver
; // Unused
2052 mStatus err
= mStatus_NoError
;
2053 const char *errormsg
= "Unknown";
2054 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2055 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2056 ServiceInstance
*si
;
2058 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2059 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2061 for (si
= x
->regs
; si
; si
= si
->next
)
2063 ExtraResourceRecord
*e
;
2064 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
2066 if ((natural_t
)e
->ClientID
== reference
)
2068 err
= RemoveRecord(&si
->srs
, e
, client
);
2072 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
2075 return mStatus_NoError
;
2078 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
2082 //*************************************************************************************************************
2085 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2087 mig_reply_error_t
*request
= msg
;
2088 mig_reply_error_t
*reply
;
2089 mach_msg_return_t mr
;
2091 (void)port
; // Unused
2092 (void)size
; // Unused
2093 (void)info
; // Unused
2095 /* allocate a reply buffer */
2096 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
2098 /* call the MiG server routine */
2099 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
2101 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
2103 if (reply
->RetCode
== MIG_NO_REPLY
)
2106 * This return code is a little tricky -- it appears that the
2107 * demux routine found an error of some sort, but since that
2108 * error would not normally get returned either to the local
2109 * user or the remote one, we pretend it's ok.
2111 CFAllocatorDeallocate(NULL
, reply
);
2116 * destroy any out-of-line data in the request buffer but don't destroy
2117 * the reply port right (since we need that to send an error message).
2119 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2120 mach_msg_destroy(&request
->Head
);
2123 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2125 /* no reply port, so destroy the reply */
2126 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2127 mach_msg_destroy(&reply
->Head
);
2128 CFAllocatorDeallocate(NULL
, reply
);
2135 * We don't want to block indefinitely because the client
2136 * isn't receiving messages from the reply port.
2137 * If we have a send-once right for the reply port, then
2138 * this isn't a concern because the send won't block.
2139 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2140 * To avoid falling off the kernel's fast RPC path unnecessarily,
2141 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2144 options
= MACH_SEND_MSG
;
2145 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2146 options
|= MACH_SEND_TIMEOUT
;
2148 mr
= mach_msg(&reply
->Head
, /* msg */
2149 options
, /* option */
2150 reply
->Head
.msgh_size
, /* send_size */
2152 MACH_PORT_NULL
, /* rcv_name */
2153 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2154 MACH_PORT_NULL
); /* notify */
2156 /* Has a message error occurred? */
2159 case MACH_SEND_INVALID_DEST
:
2160 case MACH_SEND_TIMED_OUT
:
2161 /* the reply can't be delivered, so destroy it */
2162 mach_msg_destroy(&reply
->Head
);
2166 /* Includes success case. */
2170 CFAllocatorDeallocate(NULL
, reply
);
2173 mDNSlocal kern_return_t
registerBootstrapService()
2175 kern_return_t status
;
2176 mach_port_t service_send_port
, service_rcv_port
;
2178 debugf("Registering Bootstrap Service");
2181 * See if our service name is already registered and if we have privilege to check in.
2183 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2184 if (status
== KERN_SUCCESS
)
2187 * If so, we must be a followup instance of an already defined server. In that case,
2188 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2189 * that in case we have to unregister later (which requires the privilege port).
2191 server_priv_port
= bootstrap_port
;
2192 restarting_via_mach_init
= TRUE
;
2194 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2196 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2197 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2198 if (status
!= KERN_SUCCESS
) return status
;
2200 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2201 if (status
!= KERN_SUCCESS
)
2203 mach_port_deallocate(mach_task_self(), server_priv_port
);
2207 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2208 if (status
!= KERN_SUCCESS
)
2210 mach_port_deallocate(mach_task_self(), server_priv_port
);
2211 mach_port_deallocate(mach_task_self(), service_send_port
);
2214 assert(service_send_port
== service_rcv_port
);
2218 * We have no intention of responding to requests on the service port. We are not otherwise
2219 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2220 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2221 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2223 mach_port_destroy(mach_task_self(), service_rcv_port
);
2227 mDNSlocal kern_return_t
destroyBootstrapService()
2229 debugf("Destroying Bootstrap Service");
2230 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2233 mDNSlocal
void ExitCallback(int signal
)
2235 LogMsgIdent(mDNSResponderVersionString
, "stopping");
2237 debugf("ExitCallback");
2238 if (!mDNS_DebugMode
&& !started_via_launchdaemon
&& signal
!= SIGHUP
)
2239 destroyBootstrapService();
2241 debugf("ExitCallback: Aborting MIG clients");
2242 while (DNSServiceDomainEnumerationList
)
2243 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2244 while (DNSServiceBrowserList
)
2245 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2246 while (DNSServiceResolverList
)
2247 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2248 while (DNSServiceRegistrationList
)
2249 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2251 debugf("ExitCallback: mDNS_Close");
2252 mDNS_Close(&mDNSStorage
);
2253 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2257 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2258 mDNSlocal
void HandleSIG(int signal
)
2261 debugf("HandleSIG %d", signal
);
2262 mach_msg_header_t header
;
2263 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2264 header
.msgh_remote_port
= signal_port
;
2265 header
.msgh_local_port
= MACH_PORT_NULL
;
2266 header
.msgh_size
= sizeof(header
);
2267 header
.msgh_id
= signal
;
2268 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2270 LogMsg("HandleSIG %d: mach_msg_send failed", signal
);
2271 if (signal
== SIGHUP
|| signal
== SIGTERM
|| signal
== SIGINT
) exit(-1);
2275 mDNSlocal
void INFOCallback(void)
2277 mDNSs32 utc
= mDNSPlatformUTC();
2278 DNSServiceDomainEnumeration
*e
;
2279 DNSServiceBrowser
*b
;
2280 DNSServiceResolver
*l
;
2281 DNSServiceRegistration
*r
;
2282 NetworkInterfaceInfoOSX
*i
;
2284 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2286 udsserver_info(&mDNSStorage
);
2288 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2289 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2291 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2293 DNSServiceBrowserQuestion
*qptr
;
2294 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2295 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2297 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2298 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2300 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2302 ServiceInstance
*si
;
2303 for (si
= r
->regs
; si
; si
= si
->next
)
2304 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
));
2307 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2310 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
2311 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, utc
- i
->LastSeen
);
2313 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2314 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2315 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2316 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
2317 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
2318 i
->ifinfo
.InterfaceID
,
2319 i
->ifinfo
.Advertise
? "Adv" : " ",
2320 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2324 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2327 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2329 (void)port
; // Unused
2330 (void)size
; // Unused
2331 (void)info
; // Unused
2332 mach_msg_header_t
*m
= (mach_msg_header_t
*)msg
;
2337 case SIGTERM
: ExitCallback(m
->msgh_id
); break;
2338 case SIGINFO
: INFOCallback(); break;
2339 case SIGUSR1
: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2340 mDNSMacOSXNetworkChanged(&mDNSStorage
); break;
2341 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break;
2345 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2346 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2348 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2351 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2352 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2353 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2354 mach_port_t m_port
= CFMachPortGetPort(s_port
);
2355 char *MachServerName
= OSXVers
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2356 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2357 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2358 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2359 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2364 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2366 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2370 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2371 rrcachestorage
, RR_CACHE_SIZE
,
2372 mDNS_Init_AdvertiseLocalAddresses
,
2373 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2375 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2377 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= PlatformStorage
.userhostlabel
;
2378 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= PlatformStorage
.usernicelabel
;
2380 client_death_port
= CFMachPortGetPort(d_port
);
2381 signal_port
= CFMachPortGetPort(i_port
);
2383 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
2384 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
2385 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
2389 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2393 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2395 mDNSs32 now
= mDNS_TimeNow(m
);
2397 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2399 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2400 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2401 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2402 // we then systematically lose our own looped-back packets.
2403 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2405 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2406 mDNSs32 nextevent
= mDNS_Execute(m
);
2408 if (m
->p
->NetworkChanged
)
2409 if (nextevent
- m
->p
->NetworkChanged
> 0)
2410 nextevent
= m
->p
->NetworkChanged
;
2412 // 3. Deliver any waiting browse messages to clients
2413 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2417 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2418 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2419 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2420 DNSServiceBrowser
*x
= b
;
2422 if (x
->results
) // Try to deliver the list of results
2426 DNSServiceBrowserResult
*const r
= x
->results
;
2428 domainname type
, domain
;
2429 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2430 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2431 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2432 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2433 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2434 ConvertDomainNameToCString(&type
, ctype
);
2435 ConvertDomainNameToCString(&domain
, cdom
);
2436 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2437 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2438 // If we failed to send the mach message, try again in one second
2439 if (status
== MACH_SEND_TIMED_OUT
)
2441 if (nextevent
- now
> mDNSPlatformOneSecond
)
2442 nextevent
= now
+ mDNSPlatformOneSecond
;
2447 x
->lastsuccess
= now
;
2448 x
->results
= x
->results
->next
;
2449 freeL("DNSServiceBrowserResult", r
);
2452 // If this client hasn't read a single message in the last 60 seconds, abort it
2453 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2454 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2458 DNSServiceResolver
*l
;
2459 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2460 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2463 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2464 "This places considerable burden on the network.", l
->i
.name
.c
);
2467 if (m
->p
->NotifyUser
)
2469 if (m
->p
->NotifyUser
- now
< 0)
2471 if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2473 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2474 gNotificationPrefNiceLabel
= m
->p
->usernicelabel
= m
->nicelabel
;
2475 RecordUpdatedName(m
, &gNotificationUserNiceLabel
, &gNotificationPrefNiceLabel
, "The name of your computer", "",
2476 CFSTR("To change the name of your computer, open System Preferences and click Sharing. "
2477 "Then type the name in the Computer Name field."));
2478 // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2479 m
->p
->NotifyUser
= 0;
2481 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2483 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2484 gNotificationPrefHostLabel
= m
->p
->userhostlabel
= m
->hostlabel
;
2485 RecordUpdatedName(m
, &gNotificationUserHostLabel
, &gNotificationPrefHostLabel
, "This computer’s local hostname", ".local",
2486 CFSTR("To change the local hostname, open System Preferences and click Sharing. "
2487 "Then click Edit and type the name in the Local Hostname field."));
2489 m
->p
->NotifyUser
= 0;
2492 if (nextevent
- m
->p
->NotifyUser
> 0)
2493 nextevent
= m
->p
->NotifyUser
;
2499 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2503 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2505 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2506 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2507 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2508 if (m
->NewLocalOnlyQuestions
)
2509 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2510 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2511 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2512 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2513 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2514 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2515 #ifndef UNICAST_DISABLED
2516 if (m
->timenow
- m
->uDNS_info
.nextevent
>= 0)
2517 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m
->timenow
- m
->uDNS_info
.nextevent
);
2519 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2520 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2521 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2522 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2523 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2524 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2525 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2526 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2528 mDNS_Unlock(&mDNSStorage
);
2531 mDNSexport
int main(int argc
, char **argv
)
2534 kern_return_t status
;
2536 for (i
=1; i
<argc
; i
++)
2538 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2539 if (!strcmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2542 signal(SIGHUP
, HandleSIG
); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2543 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2544 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2545 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2546 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2547 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2549 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2550 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2552 registerBootstrapService();
2553 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2554 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2555 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2558 // Avoid unnecessarily duplicating a file descriptor to itself
2559 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2560 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2561 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2562 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2566 // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
2567 // The sooner we do this, the faster the machine will boot.
2568 status
= udsserver_init();
2569 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
2571 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2572 LogMsgIdent(mDNSResponderVersionString
, "starting");
2573 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
2574 status
= mDNSDaemonInitialize();
2576 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2577 // Now that we're finished with anything privileged, switch over to running as "nobody"
2578 const struct passwd
*pw
= getpwnam("nobody");
2582 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2587 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2589 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2591 // This is the main work loop:
2592 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2593 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2594 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2595 // (4) On wakeup we first process *all* events
2596 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2597 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2599 // 1. Before going into a blocking wait call and letting our process to go sleep,
2600 // call mDNSDaemonIdle to allow any deferred work to be completed.
2601 mDNSs32 nextevent
= mDNSDaemonIdle(&mDNSStorage
);
2602 nextevent
= udsserver_idle(nextevent
);
2604 // 2. Work out how long we expect to sleep before the next scheduled task
2605 mDNSs32 ticks
= nextevent
- mDNS_TimeNow(&mDNSStorage
);
2606 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2612 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2614 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2616 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2617 // (a) our next wakeup time, or (b) an event occurs.
2618 // The 'true' parameter makes it return after handling any event that occurs
2619 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2620 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2622 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2624 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2625 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2628 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2632 LogMsg("ERROR: CFRunLoopRun Exiting.");
2633 mDNS_Close(&mDNSStorage
);
2636 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2639 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2643 // uds_daemon.c support routines /////////////////////////////////////////////
2645 // We keep a list of client-supplied event sources in PosixEventSource records
2646 struct CFSocketEventSource
2648 udsEventCallback Callback
;
2651 struct CFSocketEventSource
*Next
;
2653 CFRunLoopSourceRef RLS
;
2655 typedef struct CFSocketEventSource CFSocketEventSource
;
2657 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2659 mDNSlocal
void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
2660 // Called by CFSocket when data appears on socket
2666 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2667 source
->Callback(source
->Context
);
2670 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2671 // Arrange things so that callback is called with context when data appears on fd
2673 CFSocketEventSource
*newSource
;
2674 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2676 if (gEventSources
.LinkOffset
== 0)
2677 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2679 if (fd
>= FD_SETSIZE
|| fd
< 0)
2680 return mStatus_UnsupportedErr
;
2681 if (callback
== NULL
)
2682 return mStatus_BadParamErr
;
2684 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2685 if (NULL
== newSource
)
2686 return mStatus_NoMemoryErr
;
2688 newSource
->Callback
= callback
;
2689 newSource
->Context
= context
;
2692 cfContext
.info
= newSource
;
2693 if ( NULL
!= (newSource
->cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2694 cf_callback
, &cfContext
)) &&
2695 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0)))
2697 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2698 AddToTail(&gEventSources
, newSource
);
2704 CFSocketInvalidate(newSource
->cfs
); // Note: Also closes the underlying socket
2705 CFRelease(newSource
->cfs
);
2707 return mStatus_NoMemoryErr
;
2710 return mStatus_NoError
;
2713 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2714 // Reverse what was done in udsSupportAddFDToEventLoop().
2716 CFSocketEventSource
*iSource
;
2718 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2720 if (fd
== iSource
->fd
)
2722 RemoveFromList(&gEventSources
, iSource
);
2723 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2724 CFRunLoopSourceInvalidate(iSource
->RLS
);
2725 CFRelease(iSource
->RLS
);
2726 CFSocketInvalidate(iSource
->cfs
); // Note: Also closes the underlying socket
2727 CFRelease(iSource
->cfs
);
2729 return mStatus_NoError
;
2732 return mStatus_NoSuchNameErr
;
2735 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2736 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2737 asm(".desc ___crashreporter_info__, 0x10");
2739 // For convenience when using the "strings" command, this is the last thing in the file
2740 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";