1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22 * therefore common sense dictates that if they are part of a compound statement then they
23 * should be indented to the same level as everything else in that compound statement.
24 * Indenting curly braces at the same level as the "if" implies that curly braces are
25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27 * understand why variable y is not of type "char*" just proves the point that poor code
28 * layout leads people to unfortunate misunderstandings about how the C language really works.)
30 Change History (most recent first):
33 Revision 1.265.2.1 2006/08/29 06:24:30 cheshire
34 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
36 Revision 1.265 2006/06/29 07:32:08 cheshire
37 Added missing LogOperation logging for DNSServiceBrowse results
39 Revision 1.264 2006/06/29 05:33:30 cheshire
40 <rdar://problem/4607043> mDNSResponder conditional compilation options
42 Revision 1.263 2006/06/08 23:23:48 cheshire
43 Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
45 Revision 1.262 2006/03/18 21:49:11 cheshire
46 Added comment in ShowTaskSchedulingError(mDNS *const m)
48 Revision 1.261 2006/01/06 01:22:28 cheshire
49 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
51 Revision 1.260 2005/11/07 01:51:58 cheshire
52 <rdar://problem/4331591> Include list of configured DNS servers in SIGINFO output
54 Revision 1.259 2005/07/22 21:50:55 ksekar
55 Fix GCC 4.0/Intel compiler warnings
57 Revision 1.258 2005/07/04 22:40:26 cheshire
58 Additional debugging code to help catch memory corruption
60 Revision 1.257 2005/03/28 19:28:55 cheshire
61 Fix minor typos in LogOperation() messages
63 Revision 1.256 2005/03/17 22:01:22 cheshire
64 Tidy up alignment of lines to make code more readable
66 Revision 1.255 2005/03/09 00:48:43 cheshire
67 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
68 Move "m->p->NetworkChanged = 0;" line from caller to callee
70 Revision 1.254 2005/03/03 04:34:19 cheshire
71 <rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
73 Revision 1.253 2005/03/03 03:55:09 cheshire
74 <rdar://problem/3862944> Name collision notifications should be localized
76 Revision 1.252 2005/02/23 02:29:17 cheshire
77 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
78 Minor refinements, better variable names, improved comments
80 Revision 1.251 2005/02/21 21:31:24 ksekar
81 <rdar://problem/4015162> changed LogMsg to debugf
83 Revision 1.250 2005/02/19 01:25:04 cheshire
84 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
87 Revision 1.249 2005/02/19 00:28:45 cheshire
88 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
90 Revision 1.248 2005/02/19 00:18:34 cheshire
91 Confusing variable name -- alertMessage should be called alertHeader
93 Revision 1.247 2005/02/15 02:13:49 cheshire
94 If we did registerBootstrapService() when starting, then we must do
95 destroyBootstrapService() before exiting, or Mach init will keep restarting us.
97 Revision 1.246 2005/02/03 00:44:37 cheshire
98 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
100 Revision 1.245 2005/02/01 19:56:47 ksekar
101 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
103 Revision 1.244 2005/01/28 00:34:49 cheshire
104 Turn off "Starting time value" log message
106 Revision 1.243 2005/01/27 17:46:58 cheshire
107 Added comment about CFSocketInvalidate closing the underlying socket
109 Revision 1.242 2005/01/27 00:10:58 cheshire
110 <rdar://problem/3967867> Name change log messages every time machine boots
112 Revision 1.241 2005/01/25 17:28:06 ksekar
113 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
115 Revision 1.240 2005/01/21 02:39:18 cheshire
116 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
118 Revision 1.239 2005/01/20 00:25:01 cheshire
119 Improve validatelists() log message generation
121 Revision 1.238 2005/01/19 19:15:35 ksekar
122 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
124 Revision 1.237 2005/01/19 03:33:09 cheshire
125 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
127 Revision 1.236 2005/01/19 03:16:38 cheshire
128 <rdar://problem/3961051> CPU Spin in mDNSResponder
129 Improve detail of "Task Scheduling Error" diagnostic messages
131 Revision 1.235 2005/01/15 00:56:41 ksekar
132 <rdar://problem/3954575> Unicast services don't disappear when logging
135 Revision 1.234 2005/01/10 03:42:30 ksekar
138 Revision 1.233 2004/12/18 00:53:46 cheshire
139 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
141 Revision 1.232 2004/12/17 23:37:48 cheshire
142 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
143 (and other repetitive configuration changes)
145 Revision 1.231 2004/12/17 04:13:38 cheshire
146 Removed debugging check
148 Revision 1.230 2004/12/17 04:09:30 cheshire
149 <rdar://problem/3191011> Switch mDNSResponder to launchd
151 Revision 1.229 2004/12/16 21:51:36 cheshire
152 Remove some startup messages
154 Revision 1.228 2004/12/16 20:13:01 cheshire
155 <rdar://problem/3324626> Cache memory management improvements
157 Revision 1.227 2004/12/10 13:52:57 cheshire
158 <rdar://problem/3909995> Turn off SIGPIPE signals
160 Revision 1.226 2004/12/10 05:27:26 cheshire
161 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
163 Revision 1.225 2004/12/10 04:28:29 cheshire
164 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
166 Revision 1.224 2004/12/10 00:41:05 cheshire
167 Adjust alignment of log messages
169 Revision 1.223 2004/12/07 20:42:34 cheshire
170 Add explicit context parameter to mDNS_RemoveRecordFromService()
172 Revision 1.222 2004/12/06 21:15:23 ksekar
173 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
175 Revision 1.221 2004/11/30 03:24:04 cheshire
176 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
178 Revision 1.220 2004/11/29 23:34:31 cheshire
179 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
180 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
181 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
183 Revision 1.219 2004/11/25 01:00:56 cheshire
184 Checkin 1.217 not necessary
186 Revision 1.218 2004/11/24 20:27:19 cheshire
187 Add missing "err" parameter in LogMsg() call
189 Revision 1.217 2004/11/24 17:55:01 ksekar
190 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
192 Revision 1.216 2004/11/24 00:10:44 cheshire
193 <rdar://problem/3869241> For unicast operations, verify that service types are legal
195 Revision 1.215 2004/11/23 22:33:01 cheshire
196 <rdar://problem/3654910> Remove temporary workaround code for iChat
198 Revision 1.214 2004/11/23 22:13:59 cheshire
199 <rdar://problem/3886293> Subtype advertising broken for Mach API
201 Revision 1.213 2004/11/23 06:12:55 cheshire
202 <rdar://problem/3871405> Update wording for name conflict dialogs
204 Revision 1.212 2004/11/23 05:15:37 cheshire
205 <rdar://problem/3875830> Computer Name in use message garbled
207 Revision 1.211 2004/11/23 05:00:41 cheshire
208 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
210 Revision 1.210 2004/11/03 03:45:17 cheshire
211 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
213 Revision 1.209 2004/11/03 02:25:50 cheshire
214 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
216 Revision 1.208 2004/11/03 01:54:14 cheshire
217 Update debugging messages
219 Revision 1.207 2004/11/02 23:58:19 cheshire
220 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
222 Revision 1.206 2004/10/28 02:40:47 cheshire
223 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
225 Revision 1.205 2004/10/28 02:21:01 cheshire
226 <rdar://problem/3856500> Improve mDNSResponder signal handling
227 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
228 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
230 Revision 1.204 2004/10/27 01:57:21 cheshire
231 Add check of m->p->InterfaceList
233 Revision 1.203 2004/10/26 04:31:44 cheshire
234 Rename CountSubTypes() as ChopSubTypes()
236 Revision 1.202 2004/10/26 01:29:18 cheshire
237 Use "#if 0" instead of commenting out code
239 Revision 1.201 2004/10/25 21:41:39 ksekar
240 <rdar://problem/3852958> wide-area name conflicts can cause crash
242 Revision 1.200 2004/10/22 01:03:55 cheshire
243 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
244 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
246 Revision 1.199 2004/10/19 21:33:19 cheshire
247 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
248 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
249 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
251 Revision 1.198 2004/10/15 23:00:18 ksekar
252 <rdar://problem/3799242> Need to update LLQs on location changes
254 Revision 1.197 2004/10/12 23:38:59 ksekar
255 <rdar://problem/3837065> remove unnecessary log message
257 Revision 1.196 2004/10/04 05:56:04 cheshire
258 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
260 Revision 1.195 2004/09/30 00:24:59 ksekar
261 <rdar://problem/3695802> Dynamically update default registration domains on config change
263 Revision 1.194 2004/09/26 23:20:35 ksekar
264 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
266 Revision 1.193 2004/09/23 23:35:27 cheshire
269 Revision 1.192 2004/09/21 23:40:12 ksekar
270 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
272 Revision 1.191 2004/09/21 21:05:12 cheshire
273 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
274 into mDNSShared/uds_daemon.c
276 Revision 1.190 2004/09/21 19:51:15 cheshire
277 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
279 Revision 1.189 2004/09/21 18:17:23 cheshire
280 <rdar://problem/3785400> Add version info to mDNSResponder
282 Revision 1.188 2004/09/20 21:45:27 ksekar
285 Revision 1.187 2004/09/17 01:08:52 cheshire
286 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
287 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
288 declared in that file are ONLY appropriate to single-address-space embedded applications.
289 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
291 Revision 1.186 2004/09/16 00:24:49 cheshire
292 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
294 Revision 1.185 2004/08/25 02:01:45 cheshire
295 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
297 Revision 1.184 2004/08/19 19:04:12 ksekar
298 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
300 Revision 1.183 2004/08/14 03:22:42 cheshire
301 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
302 Add GetUserSpecifiedDDNSName() routine
303 Convert ServiceRegDomain to domainname instead of C string
304 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
306 Revision 1.182 2004/08/13 23:57:59 cheshire
307 Get rid of non-portable "_UNUSED"
309 Revision 1.181 2004/08/11 02:02:26 cheshire
310 Remove "mDNS *globalInstance" parameter from udsserver_init();
311 Move CheckForDuplicateRegistrations to uds_daemon.c
313 Revision 1.180 2004/07/13 21:24:25 rpantos
314 Fix for <rdar://problem/3701120>.
316 Revision 1.179 2004/06/19 00:02:54 cheshire
317 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
319 Revision 1.178 2004/06/18 19:10:00 cheshire
320 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
322 Revision 1.177 2004/06/16 23:14:46 ksekar
323 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
325 Revision 1.176 2004/06/11 20:27:42 cheshire
326 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
328 Revision 1.175 2004/06/10 20:23:21 cheshire
329 Also list interfaces in SIGINFO output
331 Revision 1.174 2004/06/08 18:54:48 ksekar
332 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
334 Revision 1.173 2004/06/08 17:35:12 cheshire
335 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
337 Revision 1.172 2004/06/05 00:04:26 cheshire
338 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
340 Revision 1.171 2004/06/04 08:58:30 ksekar
341 <rdar://problem/3668624>: Keychain integration for secure dynamic update
343 Revision 1.170 2004/05/30 20:01:50 ksekar
344 <rdar://problem/3668635>: wide-area default registrations should be in
345 .local too - fixed service registration when clients pass an explicit
346 domain (broken by previous checkin)
348 Revision 1.169 2004/05/30 01:30:16 ksekar
349 <rdar://problem/3668635>: wide-area default registrations should be in
352 Revision 1.168 2004/05/18 23:51:26 cheshire
353 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
355 Revision 1.167 2004/05/14 16:39:47 ksekar
356 Browse for iChat locally for now.
358 Revision 1.166 2004/05/13 21:33:52 ksekar
359 Clean up non-local registration control via config file. Force iChat
360 registrations to be local for now.
362 Revision 1.165 2004/05/13 04:54:20 ksekar
363 Unified list copy/free code. Added symetric list for
365 Revision 1.164 2004/05/12 22:03:08 ksekar
366 Made GetSearchDomainList a true platform-layer call (declaration moved
367 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
368 only on non-OSX platforms. Changed call to return a copy of the list
369 to avoid shared memory issues. Added a routine to free the list.
371 Revision 1.163 2004/05/12 02:03:25 ksekar
372 Non-local domains will only be browsed by default, and show up in
373 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
375 Revision 1.162 2004/04/14 23:09:29 ksekar
376 Support for TSIG signed dynamic updates.
378 Revision 1.161 2004/04/07 01:20:04 cheshire
379 Hash slot value should be unsigned
381 Revision 1.160 2004/04/06 19:51:24 cheshire
382 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
383 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
385 Revision 1.159 2004/04/03 01:36:55 cheshire
386 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
387 If "nobody" user doesn't exist, log a message and continue as "root"
389 Revision 1.158 2004/04/02 21:39:05 cheshire
390 Fix errors in comments
392 Revision 1.157 2004/03/19 18:49:10 ksekar
393 Increased size check in freeL() to account for LargeCacheRecord
394 structs larger than 8k
396 Revision 1.156 2004/03/19 18:19:19 ksekar
397 Fixed daemon.c to compile with malloc debugging turned on.
399 Revision 1.155 2004/03/13 01:57:34 ksekar
400 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
402 Revision 1.154 2004/03/12 08:42:47 cheshire
403 <rdar://problem/3548256>: Should not allow empty string for resolve domain
405 Revision 1.153 2004/03/12 08:08:51 cheshire
408 Revision 1.152 2004/02/05 19:39:29 cheshire
409 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
410 so that all platforms get this functionality
412 Revision 1.151 2004/02/03 22:35:34 cheshire
413 <rdar://problem/3548256>: Should not allow empty string for resolve domain
415 Revision 1.150 2004/01/28 21:14:23 cheshire
416 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
418 Revision 1.149 2004/01/28 02:30:08 ksekar
419 Added default Search Domains to unicast browsing, controlled via
420 Networking sharing prefs pane. Stopped sending unicast messages on
421 every interface. Fixed unicast resolving via mach-port API.
423 Revision 1.148 2004/01/25 00:03:20 cheshire
424 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
426 Revision 1.147 2004/01/19 19:51:46 cheshire
427 Fix compiler error (mixed declarations and code) on some versions of Linux
429 Revision 1.146 2003/12/08 21:00:46 rpantos
430 Changes to support mDNSResponder on Linux.
432 Revision 1.145 2003/12/05 22:08:07 cheshire
433 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
435 Revision 1.144 2003/11/19 23:21:08 ksekar
436 <rdar://problem/3486646>: config change handler not called for dns-sd services
438 Revision 1.143 2003/11/14 21:18:32 cheshire
439 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
440 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
442 Revision 1.142 2003/11/08 22:18:29 cheshire
443 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
445 Revision 1.141 2003/11/07 02:30:57 cheshire
446 Also check per-slot cache use counts in SIGINFO state log
448 Revision 1.140 2003/10/21 19:58:26 cheshire
449 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
451 Revision 1.139 2003/10/21 00:10:18 rpantos
452 <rdar://problem/3409401>: mDNSResponder should not run as root
454 Revision 1.138 2003/10/07 20:16:58 cheshire
455 Shorten syslog message a bit
457 Revision 1.137 2003/09/23 02:12:43 cheshire
458 Also include port number in list of services registered via new UDS API
460 Revision 1.136 2003/09/23 02:07:25 cheshire
461 Include port number in DNSServiceRegistration START/STOP messages
463 Revision 1.135 2003/09/23 01:34:02 cheshire
464 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
466 Revision 1.134 2003/08/21 20:01:37 cheshire
467 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
469 Revision 1.133 2003/08/20 23:39:31 cheshire
470 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
472 Revision 1.132 2003/08/20 01:44:56 cheshire
473 Fix errors in LogOperation() calls (only used for debugging)
475 Revision 1.131 2003/08/19 05:39:43 cheshire
476 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
478 Revision 1.130 2003/08/16 03:39:01 cheshire
479 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
481 Revision 1.129 2003/08/15 20:16:03 cheshire
482 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
483 We want to avoid touching the rdata pages, so we don't page them in.
484 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
485 Moved this from the RData to the ResourceRecord object.
486 2. To avoid unnecessarily touching the rdata just to compare it,
487 compute a hash of the rdata and store the hash in the ResourceRecord object.
489 Revision 1.128 2003/08/14 19:30:36 cheshire
490 <rdar://problem/3378473> Include list of cache records in SIGINFO output
492 Revision 1.127 2003/08/14 02:18:21 cheshire
493 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
495 Revision 1.126 2003/08/12 19:56:25 cheshire
498 Revision 1.125 2003/08/08 18:36:04 cheshire
499 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
501 Revision 1.124 2003/07/25 18:28:23 cheshire
502 Minor fix to error messages in syslog: Display string parameters with quotes
504 Revision 1.123 2003/07/23 17:45:28 cheshire
505 <rdar://problem/3339388> mDNSResponder leaks a bit
506 Don't allocate memory for the reply until after we've verified that the reply is valid
508 Revision 1.122 2003/07/23 00:00:04 cheshire
511 Revision 1.121 2003/07/20 03:38:51 ksekar
512 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
514 Revision 1.120 2003/07/18 00:30:00 cheshire
515 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
517 Revision 1.119 2003/07/17 19:08:58 cheshire
518 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
520 Revision 1.118 2003/07/15 21:12:28 cheshire
521 Added extra debugging checks in validatelists() (not used in final shipping version)
523 Revision 1.117 2003/07/15 01:55:15 cheshire
524 <rdar://problem/3315777> Need to implement service registration with subtypes
526 Revision 1.116 2003/07/02 21:19:51 cheshire
527 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
529 Revision 1.115 2003/07/02 02:41:24 cheshire
530 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
532 Revision 1.114 2003/07/01 21:10:20 cheshire
533 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
535 Revision 1.113 2003/06/28 17:27:43 vlubet
536 <rdar://problem/3221246> Redirect standard input, standard output, and
537 standard error file descriptors to /dev/null just like any other
540 Revision 1.112 2003/06/25 23:42:19 ksekar
541 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
542 Reviewed by: Stuart Cheshire
543 Added files necessary to implement Unix domain sockets based enhanced
544 DNS-SD APIs, and integrated with existing Mach-port based daemon.
546 Revision 1.111 2003/06/11 01:02:43 cheshire
547 <rdar://problem/3287858> mDNSResponder binary compatibility
548 Make single binary that can run on both Jaguar and Panther.
550 Revision 1.110 2003/06/10 01:14:11 cheshire
551 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
553 Revision 1.109 2003/06/06 19:53:43 cheshire
554 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
555 (Global search-and-replace; no functional change to code execution.)
557 Revision 1.108 2003/06/06 14:08:06 cheshire
558 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
560 Revision 1.107 2003/05/29 05:44:55 cheshire
561 Minor fixes to log messages
563 Revision 1.106 2003/05/27 18:30:55 cheshire
564 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
565 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
567 Revision 1.105 2003/05/26 03:21:29 cheshire
568 Tidy up address structure naming:
569 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
570 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
571 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
573 Revision 1.104 2003/05/26 00:42:06 cheshire
574 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
576 Revision 1.103 2003/05/23 23:07:44 cheshire
577 <rdar://problem/3268199> Must not write to stderr when running as daemon
579 Revision 1.102 2003/05/22 01:32:31 cheshire
580 Fix typo in Log message format string
582 Revision 1.101 2003/05/22 00:26:55 cheshire
583 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
584 Modify error message to explain that this is technically legal, but may indicate a bug.
586 Revision 1.100 2003/05/21 21:02:24 ksekar
587 <rdar://problem/3247035>: Service should be prefixed
588 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
589 Mach message port to "com.apple.mDNSResponder.
591 Revision 1.99 2003/05/21 17:33:49 cheshire
592 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
594 Revision 1.98 2003/05/20 00:33:07 cheshire
595 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
596 SIGHUP now writes state summary to syslog
598 Revision 1.97 2003/05/08 00:19:08 cheshire
599 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
601 Revision 1.96 2003/05/07 22:10:46 cheshire
602 <rdar://problem/3250330> Add a few more error logging messages
604 Revision 1.95 2003/05/07 19:20:17 cheshire
605 <rdar://problem/3251391> Add version number to mDNSResponder builds
607 Revision 1.94 2003/05/07 00:28:18 cheshire
608 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
610 Revision 1.93 2003/05/06 00:00:49 cheshire
611 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
613 Revision 1.92 2003/04/04 20:38:57 cheshire
618 #include <mach/mach.h>
619 #include <mach/mach_error.h>
620 #include <servers/bootstrap.h>
621 #include <sys/types.h>
626 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
628 #include "DNSServiceDiscoveryRequestServer.h"
629 #include "DNSServiceDiscoveryReply.h"
631 #include "DNSCommon.h"
632 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
634 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
636 #include "GenLinkedList.h"
638 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
640 //*************************************************************************************************************
643 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
644 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
645 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
646 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
647 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
649 //*************************************************************************************************************
652 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
653 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
654 static mDNS_PlatformSupport PlatformStorage
;
656 // Start off with a default cache of 16K (about 100 records)
657 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
658 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
660 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
661 static mach_port_t client_death_port
= MACH_PORT_NULL
;
662 static mach_port_t signal_port
= MACH_PORT_NULL
;
663 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
665 // mDNS Mach Message Timeout, in milliseconds.
666 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
667 // fails to service its mach message queue, but long enough to give a well-written
668 // client a chance to service its mach message queue without getting cut off.
669 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
670 // even extra-slow clients a fair chance before we cut them off.
671 #define MDNS_MM_TIMEOUT 250
673 static int restarting_via_mach_init
= 0;
674 static int started_via_launchdaemon
= 0;
678 //*************************************************************************************************************
679 // Active client list structures
681 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
682 struct DNSServiceDomainEnumeration_struct
684 DNSServiceDomainEnumeration
*next
;
685 mach_port_t ClientMachPort
;
686 DNSQuestion dom
; // Question asking for domains
687 DNSQuestion def
; // Question asking for default domain
690 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
691 struct DNSServiceBrowserResult_struct
693 DNSServiceBrowserResult
*next
;
698 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
700 typedef struct DNSServiceBrowserQuestion
702 struct DNSServiceBrowserQuestion
*next
;
705 } DNSServiceBrowserQuestion
;
707 struct DNSServiceBrowser_struct
709 DNSServiceBrowser
*next
;
710 mach_port_t ClientMachPort
;
711 DNSServiceBrowserQuestion
*qlist
;
712 DNSServiceBrowserResult
*results
;
714 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
715 domainname type
; // registration type
718 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
719 struct DNSServiceResolver_struct
721 DNSServiceResolver
*next
;
722 mach_port_t ClientMachPort
;
728 // A single registered service: ServiceRecordSet + bookkeeping
729 // Note that we duplicate some fields from parent DNSServiceRegistration object
730 // to facilitate cleanup, when instances and parent may be deallocated at different times.
731 typedef struct ServiceInstance
733 struct ServiceInstance
*next
;
734 mach_port_t ClientMachPort
;
735 mDNSBool autoname
; // Set if this name is tied to the Computer Name
736 mDNSBool autorename
; // Set if we just got a name conflict and now need to automatically pick a new name
739 ServiceRecordSet srs
;
740 // Don't add any fields after ServiceRecordSet.
741 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
744 // A client-created service. May reference several ServiceInstance objects if default
745 // settings cause registration in multiple domains.
746 typedef struct DNSServiceRegistration
748 struct DNSServiceRegistration
*next
;
749 mach_port_t ClientMachPort
;
750 mDNSBool DefaultDomain
;
754 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
755 domainlabel name
; // used only if autoname is false
758 unsigned char txtinfo
[1024];
761 ServiceInstance
*regs
;
762 } DNSServiceRegistration
;
764 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
765 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
766 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
767 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
769 //*************************************************************************************************************
770 // General Utility Functions
772 #if MACOSX_MDNS_MALLOC_DEBUGGING
774 char _malloc_options
[] = "AXZ";
776 mDNSexport
void LogMemCorruption(const char *format
, ...)
780 va_start(ptr
,format
);
781 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
783 LogMsg("!!!! %s !!!!", buffer
);
784 NotifyOfElusiveBug("Memory Corruption", buffer
);
785 //*(long*)0 = -1; // Trick to crash and get a stack trace right here, if that's what we want
788 mDNSlocal
void validatelists(mDNS
*const m
)
790 // Check Mach client lists
792 DNSServiceDomainEnumeration
*e
;
793 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
794 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
795 LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e
, e
->ClientMachPort
);
797 DNSServiceBrowser
*b
;
798 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
799 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
800 LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b
, b
->ClientMachPort
);
802 DNSServiceResolver
*l
;
803 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
804 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
805 LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l
, l
->ClientMachPort
);
807 DNSServiceRegistration
*r
;
808 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
809 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
810 LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r
, r
->ClientMachPort
);
812 // Check UDS client lists
815 // Check core mDNS lists
817 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
819 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
820 LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
821 if (rr
->resrec
.name
!= &rr
->namestorage
)
822 LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
823 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
826 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
827 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
828 LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
831 for (q
= m
->Questions
; q
; q
=q
->next
)
832 if (q
->ThisQInterval
== (mDNSs32
)~0)
833 LogMemCorruption("Questions list: %p is garbage (%lX)", q
, q
->ThisQInterval
);
838 FORALL_CACHERECORDS(slot
, cg
, cr
)
839 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
840 LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot
, rr
, rr
->resrec
.RecordType
);
842 // Check platform-layer lists
844 NetworkInterfaceInfoOSX
*i
;
845 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
847 LogMemCorruption("InterfaceList: %p is garbage", i
);
851 for (q
= m
->uDNS_info
.ActiveQueries
; q
; q
=q
->next
)
852 if (*(long*)q
== (mDNSs32
)~0)
853 LogMemCorruption("uDNS_info.ActiveQueries: %p is garbage (%lX)", q
, *(long*)q
);
856 for (s
= m
->uDNS_info
.ServiceRegistrations
; s
; s
=s
->next
)
857 if (s
->next
== (ServiceRecordSet
*)~0)
858 LogMemCorruption("uDNS_info.ServiceRegistrations: %p is garbage (%lX)", s
, s
->next
);
860 for (rr
= m
->uDNS_info
.RecordRegistrations
; rr
; rr
=rr
->next
)
862 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
863 LogMemCorruption("uDNS_info.RecordRegistrations: %p is garbage (%X)", rr
, rr
->resrec
.RecordType
);
864 if (rr
->resrec
.name
!= &rr
->namestorage
)
865 LogMemCorruption("uDNS_info.RecordRegistrations: %p name %p does not point to namestorage %p %##s",
866 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
870 for (n
= m
->uDNS_info
.NATTraversals
; n
; n
=n
->next
)
871 if (n
->op
> 2) LogMemCorruption("uDNS_info.NATTraversals: %p is garbage", n
);
873 for (n
= m
->uDNS_info
.LLQNatInfo
; n
; n
=n
->next
)
874 if (n
->op
> 2) LogMemCorruption("uDNS_info.LLQNatInfo: %p is garbage", n
);
877 void *mallocL(char *msg
, unsigned int size
)
879 unsigned long *mem
= malloc(size
+8);
882 LogMsg("malloc( %s : %d ) failed", msg
, size
);
887 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
890 //bzero(&mem[2], size);
891 memset(&mem
[2], 0xFF, size
);
892 validatelists(&mDNSStorage
);
897 void freeL(char *msg
, void *x
)
900 LogMsg("free( %s @ NULL )!", msg
);
903 unsigned long *mem
= ((unsigned long *)x
) - 2;
904 if (mem
[0] != 0xDEAD1234)
905 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
907 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
908 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
909 //bzero(mem, mem[1]+8);
910 memset(mem
, 0xFF, mem
[1]+8);
911 validatelists(&mDNSStorage
);
918 //*************************************************************************************************************
919 // Client Death Detection
921 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
923 ServiceRecordSet
*s
= &x
->srs
;
924 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
928 e
->r
.RecordContext
= e
;
931 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
934 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
935 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
937 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
938 freeL("ServiceInstance", x
);
941 // AbortClient finds whatever client is identified by the given Mach port,
942 // stops whatever operation that client was doing, and frees its memory.
943 // In the case of a service registration, the actual freeing may be deferred
944 // until we get the mStatus_MemFree message, if necessary
945 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
947 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
948 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
949 DNSServiceResolver
**l
= &DNSServiceResolverList
;
950 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
952 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
955 DNSServiceDomainEnumeration
*x
= *e
;
958 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
959 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
960 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
961 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
962 freeL("DNSServiceDomainEnumeration", x
);
966 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
969 DNSServiceBrowser
*x
= *b
;
970 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
975 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
976 else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
977 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
980 freeL("DNSServiceBrowserQuestion", freePtr
);
984 DNSServiceBrowserResult
*r
= x
->results
;
985 x
->results
= x
->results
->next
;
986 freeL("DNSServiceBrowserResult", r
);
988 freeL("DNSServiceBrowser", x
);
992 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
995 DNSServiceResolver
*x
= *l
;
998 LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
999 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
1000 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
1001 freeL("DNSServiceResolver", x
);
1005 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
1008 ServiceInstance
*si
= NULL
;
1009 DNSServiceRegistration
*x
= *r
;
1015 ServiceInstance
*instance
= si
;
1017 instance
->autorename
= mDNSfalse
;
1018 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
);
1019 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
1021 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
1022 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
1023 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
1024 // the list, so we should go ahead and free the memory right now
1025 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
1028 freeL("DNSServiceRegistration", x
);
1032 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
1035 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
1037 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
1039 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1040 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1041 DNSServiceResolver
*l
= DNSServiceResolverList
;
1042 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1043 DNSServiceBrowserQuestion
*qptr
;
1045 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1046 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1047 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1048 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1050 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
1053 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1054 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
1056 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
1059 ServiceInstance
*si
;
1060 for (si
= r
->regs
; si
; si
= si
->next
)
1061 LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
1063 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
1068 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
1070 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
1071 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1072 DNSServiceResolver
*l
= DNSServiceResolverList
;
1073 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
1074 DNSServiceBrowserQuestion
*qptr
;
1076 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
1077 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
1078 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
1079 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
1080 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
1083 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1084 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
1086 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
1087 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
1088 return(e
|| b
|| l
|| r
);
1091 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
1093 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
1094 (void)unusedport
; // Unused
1095 (void)size
; // Unused
1096 (void)info
; // Unused
1097 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
1099 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
1100 AbortClient(deathMessage
->not_port
, NULL
);
1102 /* Deallocate the send right that came in the dead name notification */
1103 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
1107 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
1110 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
1111 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
1112 // If the port already died while we were thinking about it, then abort the operation right away
1113 if (r
!= KERN_SUCCESS
)
1114 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1117 //*************************************************************************************************************
1118 // Domain Enumeration
1120 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1122 kern_return_t status
;
1124 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1125 DNSServiceDomainEnumerationReplyResultType rt
;
1126 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1128 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1129 if (answer
->rrtype
!= kDNSType_PTR
) return;
1130 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1134 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1135 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1139 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1143 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1144 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1145 !AddRecord
? "RemoveDomain" :
1146 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1148 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1149 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1150 if (status
== MACH_SEND_TIMED_OUT
)
1151 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1154 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1157 // Check client parameter
1158 (void)unusedserver
; // Unused
1159 mStatus err
= mStatus_NoError
;
1160 const char *errormsg
= "Unknown";
1161 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1162 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1164 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1165 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1167 // Allocate memory, and handle failure
1168 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1169 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1171 // Set up object, and link into list
1172 x
->ClientMachPort
= client
;
1173 x
->next
= DNSServiceDomainEnumerationList
;
1174 DNSServiceDomainEnumerationList
= x
;
1176 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1179 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1180 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1181 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1183 // Succeeded: Wrap up and return
1184 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1185 EnableDeathNotificationForClient(client
, x
);
1186 return(mStatus_NoError
);
1189 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
1193 //*************************************************************************************************************
1194 // Browse for services
1196 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1200 if (answer
->rrtype
!= kDNSType_PTR
)
1201 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1204 domainname type
, domain
;
1205 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1207 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1208 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1212 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1213 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1215 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1216 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1218 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1219 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1222 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1223 DNSServiceBrowserResult
**p
= &browser
->results
;
1224 while (*p
) p
= &(*p
)->next
;
1227 LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
1228 browser
->ClientMachPort
, question
->qname
.c
, DNSTypeName(question
->qtype
), AddRecord
? "Add" : "Rmv", RRDisplayString(m
, answer
));
1231 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1233 mStatus err
= mStatus_NoError
;
1234 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1236 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1238 if (SameDomainName(&ptr
->q
.qname
, d
))
1239 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1242 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1243 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1244 AssignDomainName(&question
->domain
, d
);
1245 question
->next
= browser
->qlist
;
1246 browser
->qlist
= question
;
1247 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1248 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1249 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1253 mDNSexport
void DefaultBrowseDomainChanged(const domainname
*d
, mDNSBool add
)
1255 DNSServiceBrowser
*ptr
;
1257 debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
1258 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1260 if (ptr
->DefaultDomain
)
1264 mStatus err
= AddDomainToBrowser(ptr
, d
);
1265 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1269 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1272 if (SameDomainName(&(*q
)->domain
, d
))
1274 DNSServiceBrowserQuestion
*remove
= *q
;
1276 if (remove
->q
.LongLived
)
1278 // Give goodbyes for known answers.
1279 // Note that this a special case where we know that the QuestionCallback function is our own
1280 // code (it's FoundInstance), and that callback routine doesn't ever cancel its operation, so we
1281 // don't need to guard against the question being cancelled mid-loop the way the mDNSCore routines do.
1282 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
1283 while (ka
) { remove
->q
.QuestionCallback(&mDNSStorage
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
1285 mDNS_StopBrowse(&mDNSStorage
, &remove
->q
);
1286 freeL("DNSServiceBrowserQuestion", remove
);
1291 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1297 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1298 DNSCString regtype
, DNSCString domain
)
1300 // Check client parameter
1301 (void)unusedserver
; // Unused
1302 mStatus err
= mStatus_NoError
;
1303 const char *errormsg
= "Unknown";
1304 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
1306 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1307 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1309 // Check other parameters
1312 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1313 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1314 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1315 { errormsg
= "Bad Service SubType"; goto badparam
; }
1316 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1318 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1319 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1321 // Allocate memory, and handle failure
1322 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1323 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1325 // Set up object, and link into list
1326 AssignDomainName(&x
->type
, &t
);
1327 x
->ClientMachPort
= client
;
1331 x
->next
= DNSServiceBrowserList
;
1332 DNSServiceBrowserList
= x
;
1336 // Start browser for an explicit domain
1337 x
->DefaultDomain
= mDNSfalse
;
1338 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1339 err
= AddDomainToBrowser(x
, &d
);
1340 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1344 // Start browser on all domains
1345 x
->DefaultDomain
= mDNStrue
;
1346 SearchDomains
= mDNSPlatformGetSearchDomainList();
1347 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1348 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1350 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1353 // only terminally bail if .local fails
1354 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1355 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1356 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1361 // Succeeded: Wrap up and return
1362 EnableDeathNotificationForClient(client
, x
);
1363 mDNS_FreeDNameList(SearchDomains
);
1364 return(mStatus_NoError
);
1367 err
= mStatus_BadParamErr
;
1369 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1370 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
1374 //*************************************************************************************************************
1375 // Resolve Service Info
1377 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1379 kern_return_t status
;
1380 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1381 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1382 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1383 struct sockaddr_storage interface
;
1384 struct sockaddr_storage address
;
1386 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1389 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1391 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1393 bzero(&interface
, sizeof(interface
));
1394 bzero(&address
, sizeof(address
));
1396 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1398 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1399 sin
->sin_len
= sizeof(*sin
);
1400 sin
->sin_family
= AF_INET
;
1402 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1404 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1406 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1407 sin6
->sin6_len
= sizeof(*sin6
);
1408 sin6
->sin6_family
= AF_INET6
;
1409 sin6
->sin6_flowinfo
= 0;
1410 sin6
->sin6_port
= 0;
1411 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1412 sin6
->sin6_scope_id
= ifx
->scope_id
;
1415 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1417 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1418 sin
->sin_len
= sizeof(*sin
);
1419 sin
->sin_family
= AF_INET
;
1420 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1421 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1425 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1426 sin6
->sin6_len
= sizeof(*sin6
);
1427 sin6
->sin6_family
= AF_INET6
;
1428 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1429 sin6
->sin6_flowinfo
= 0;
1430 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1431 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1434 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1435 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1436 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1437 // ASCII-1 characters are used in the C-string as boundary markers,
1438 // to indicate the boundaries between the original constituent P-strings.
1439 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1442 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1446 pstrlen
= query
->info
->TXTinfo
[i
];
1449 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1451 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1452 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1453 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1454 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1455 if (status
== MACH_SEND_TIMED_OUT
)
1456 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1459 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1460 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1462 // Check client parameter
1463 (void)unusedserver
; // Unused
1464 mStatus err
= mStatus_NoError
;
1465 const char *errormsg
= "Unknown";
1466 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1467 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1469 // Check other parameters
1471 domainname t
, d
, srv
;
1472 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1473 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1474 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1475 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1477 // Allocate memory, and handle failure
1478 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1479 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1481 // Set up object, and link into list
1482 x
->ClientMachPort
= client
;
1483 x
->i
.InterfaceID
= mDNSInterface_Any
;
1485 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1486 x
->next
= DNSServiceResolverList
;
1487 DNSServiceResolverList
= x
;
1490 LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
);
1491 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1492 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1494 // Succeeded: Wrap up and return
1495 EnableDeathNotificationForClient(client
, x
);
1496 return(mStatus_NoError
);
1499 err
= mStatus_BadParamErr
;
1501 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1505 //*************************************************************************************************************
1508 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1510 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1513 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1515 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1517 if (result
== mStatus_NoError
)
1519 kern_return_t status
;
1520 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1521 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1522 if (status
== MACH_SEND_TIMED_OUT
)
1523 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1524 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1525 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1528 else if (result
== mStatus_NameConflict
)
1530 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1531 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1532 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1533 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1535 // On conflict for an autoname service, rename and reregister *all* autoname services
1536 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1537 m
->MainCallback(m
, mStatus_ConfigChanged
);
1539 else if (si
->autoname
)
1541 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1546 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1547 // of their registration in the usual way (which we will catch via client death notification).
1548 // If the Mach queue is full, we forcibly abort the client immediately.
1549 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1550 if (status
== MACH_SEND_TIMED_OUT
)
1551 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1555 else if (result
== mStatus_MemFree
)
1559 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1560 si
->autorename
= mDNSfalse
;
1561 si
->name
= m
->nicelabel
;
1562 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1566 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1567 DNSServiceRegistration
*r
;
1568 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1570 ServiceInstance
*sp
= r
->regs
, *prev
= NULL
;
1575 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
->c
);
1576 if (prev
) prev
->next
= sp
->next
;
1577 else r
->regs
= sp
->next
;
1585 FreeServiceInstance(si
);
1589 else if (result
!= mStatus_NATTraversal
)
1590 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1593 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1596 ServiceInstance
*si
= NULL
;
1597 AuthRecord
*SubTypes
= NULL
;
1599 for (si
= x
->regs
; si
; si
= si
->next
)
1601 if (SameDomainName(&si
->domain
, domain
))
1602 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1605 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1606 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1608 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1609 if (!si
) return mStatus_NoMemoryErr
;
1611 si
->ClientMachPort
= x
->ClientMachPort
;
1612 si
->autorename
= mDNSfalse
;
1613 si
->autoname
= x
->autoname
;
1614 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1615 si
->domain
= *domain
;
1617 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
);
1625 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1626 freeL("ServiceInstance", si
);
1631 mDNSexport
void DefaultRegDomainChanged(const domainname
*d
, mDNSBool add
)
1633 DNSServiceRegistration
*reg
;
1635 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1637 if (reg
->DefaultDomain
)
1641 AddServiceInstance(reg
, d
);
1645 ServiceInstance
*si
= reg
->regs
, *prev
= NULL
;
1648 if (SameDomainName(&si
->domain
, d
))
1650 if (prev
) prev
->next
= si
->next
;
1651 else reg
->regs
= si
->next
;
1652 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
))
1653 FreeServiceInstance(si
); // only free memory synchronously on error
1659 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed
1665 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1666 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1668 (void)unusedserver
; // Unused
1669 mStatus err
= mStatus_NoError
;
1670 const char *errormsg
= "Unknown";
1672 // older versions of this code passed the port via mach IPC as an int.
1673 // we continue to pass it as 4 bytes to maintain binary compatibility,
1674 // but now ensure that the network byte order is preserved by using a struct
1676 port
.b
[0] = IpPort
.bytes
[2];
1677 port
.b
[1] = IpPort
.bytes
[3];
1679 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1680 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1682 // Check for sub-types after the service type
1683 size_t reglen
= strlen(regtype
) + 1;
1684 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1685 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1686 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1688 // Check other parameters
1692 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1693 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1694 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1695 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1696 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1698 unsigned char txtinfo
[1024] = "";
1699 unsigned int data_len
= 0;
1700 unsigned int size
= sizeof(RDataBody
);
1701 unsigned char *pstring
= &txtinfo
[data_len
];
1702 char *ptr
= txtRecord
;
1704 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1705 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1706 // Hence we have to convert the C-string to a P-string.
1707 // ASCII-1 characters are allowed in the C-string as boundary markers,
1708 // so that a single C-string can be used to represent one or more P-strings.
1711 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1712 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1714 pstring
= &txtinfo
[data_len
];
1720 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1721 pstring
[++pstring
[0]] = *ptr
++;
1726 if (size
< data_len
)
1729 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1730 // a port number of zero. When two instances of the protected client are allowed to run on one
1731 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1732 if (port
.NotAnInteger
)
1734 int count
= CountExistingRegistrations(&srv
, port
);
1736 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1737 client
, count
+1, srv
.c
, mDNSVal16(port
));
1740 // Allocate memory, and handle failure
1741 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1742 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1743 bzero(x
, sizeof(*x
));
1745 // Set up object, and link into list
1746 x
->ClientMachPort
= client
;
1747 x
->DefaultDomain
= !domain
[0];
1748 x
->autoname
= (!name
[0]);
1750 x
->NumSubTypes
= NumSubTypes
;
1751 memcpy(x
->regtype
, regtype
, reglen
);
1755 memcpy(x
->txtinfo
, txtinfo
, 1024);
1756 x
->txt_len
= data_len
;
1760 x
->next
= DNSServiceRegistrationList
;
1761 DNSServiceRegistrationList
= x
;
1763 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1764 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1766 err
= AddServiceInstance(x
, &d
);
1767 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1769 if (x
->DefaultDomain
)
1771 DNameListElem
*ptr
, *regdomains
= mDNSPlatformGetRegDomainList();
1772 for (ptr
= regdomains
; ptr
; ptr
= ptr
->next
)
1773 AddServiceInstance(x
, &ptr
->name
);
1774 mDNS_FreeDNameList(regdomains
);
1777 // Succeeded: Wrap up and return
1778 EnableDeathNotificationForClient(client
, x
);
1779 return(mStatus_NoError
);
1782 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1784 err
= mStatus_BadParamErr
;
1786 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1787 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1791 mDNSlocal domainlabel gNotificationPrefHostLabel
; // The prefs as they were the last time we saw them
1792 mDNSlocal domainlabel gNotificationPrefNiceLabel
;
1793 mDNSlocal domainlabel gNotificationUserHostLabel
; // The prefs as they were the last time the user changed them
1794 mDNSlocal domainlabel gNotificationUserNiceLabel
;
1796 #ifndef NO_CFUSERNOTIFICATION
1797 mDNSlocal CFUserNotificationRef gNotification
= NULL
;
1798 mDNSlocal CFRunLoopSourceRef gNotificationRLS
= NULL
;
1800 mDNSlocal
void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
1802 (void)responseFlags
; // Unused
1803 if (userNotification
!= gNotification
) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
1804 if (gNotificationRLS
)
1806 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1807 CFRelease(gNotificationRLS
);
1808 gNotificationRLS
= NULL
;
1809 CFRelease(gNotification
);
1810 gNotification
= NULL
;
1812 // By dismissing the alert, the user has conceptually acknowleged the rename.
1813 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
1814 // If we get *another* conflict, the new alert should refer to the 'old'.
1815 // name as now being "computer-2.local", not "computer.local"
1816 gNotificationUserHostLabel
= gNotificationPrefHostLabel
;
1817 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
;
1820 mDNSlocal
void ShowNameConflictNotification(CFStringRef header
, CFStringRef subtext
)
1822 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1823 if (!dictionary
) return;
1824 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
1825 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
1827 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
1828 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
1830 if (gNotification
) // If notification already on-screen, update it in place
1831 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
1832 else // else, we need to create it
1835 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
1836 if (!gNotification
) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
1837 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
1838 if (!gNotificationRLS
) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
1839 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
);
1842 CFRelease(dictionary
);
1844 #endif /* NO_CFUSERNOTIFICATION */
1846 // This updates either the text of the field currently labelled "Local Hostname",
1847 // or the text of the field currently labelled "Computer Name"
1848 // in the Sharing Prefs Control Panel
1849 mDNSlocal
void RecordUpdatedName(const mDNS
*const m
, const domainlabel
*const olddl
, const domainlabel
*const newdl
,
1850 const char *const msg
, const char *const suffix
, const CFStringRef subtext
)
1852 char oldname
[MAX_DOMAIN_LABEL
+1];
1853 char newname
[MAX_DOMAIN_LABEL
+1];
1854 ConvertDomainLabelToCString_unescaped(olddl
, oldname
);
1855 ConvertDomainLabelToCString_unescaped(newdl
, newname
);
1856 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
1857 const CFStringRef cfnewname
= CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
);
1858 const CFStringRef f1
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1859 const CFStringRef f2
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
);
1860 const SCPreferencesRef session
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
);
1861 if (!cfoldname
|| !cfnewname
|| !f1
|| !f2
|| !session
|| !SCPreferencesLock(session
, 0)) // If we can't get the lock don't wait
1862 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1865 const CFStringRef s0
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1866 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
);
1867 const CFStringRef s2
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
);
1868 // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
1869 // element of the array individually for us, and then concatenate the results to make the final message.
1870 // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
1871 // On Panther this does not work, so we just build the string directly, and it will not be translated.
1872 const CFMutableStringRef alertHeader
=
1873 (OSXVers
< 8) ? CFStringCreateMutable(NULL
, 0) : (CFMutableStringRef
)CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1875 if (newdl
== &gNotificationPrefHostLabel
) result
= SCPreferencesSetLocalHostName(session
, cfnewname
);
1876 else result
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
);
1877 if (!result
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0
|| !s1
|| !s2
|| !alertHeader
)
1878 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1879 else if (m
->p
->NotifyUser
)
1881 #ifndef NO_CFUSERNOTIFICATION
1884 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
1887 CFRelease(userName
);
1888 typedef void CFStringAppendFN(CFMutableStringRef theString
, CFStringRef appendedString
);
1889 CFStringAppendFN
*const append
= (OSXVers
< 8) ? &CFStringAppend
: (CFStringAppendFN
*)&CFArrayAppendValue
;
1890 append(alertHeader
, s0
);
1891 append(alertHeader
, s1
);
1892 append(alertHeader
, CFSTR("is already in use on this network."));
1893 append(alertHeader
, CFSTR(" "));
1894 append(alertHeader
, CFSTR("The name has been changed to"));
1895 append(alertHeader
, s2
);
1896 append(alertHeader
, CFSTR("automatically."));
1897 ShowNameConflictNotification(alertHeader
, subtext
);
1901 #endif /* NO_CFUSERNOTIFICATION */
1903 if (s0
) CFRelease(s0
);
1904 if (s1
) CFRelease(s1
);
1905 if (s2
) CFRelease(s2
);
1906 if (alertHeader
) CFRelease(alertHeader
);
1907 SCPreferencesUnlock(session
);
1909 if (cfoldname
) CFRelease(cfoldname
);
1910 if (cfnewname
) CFRelease(cfnewname
);
1911 if (f1
) CFRelease(f1
);
1912 if (f2
) CFRelease(f2
);
1913 if (session
) CFRelease(session
);
1916 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1919 if (result
== mStatus_NoError
)
1921 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
1922 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
);
1924 else if (result
== mStatus_ConfigChanged
)
1926 // If the user-specified hostlabel from System Configuration has changed since the last time
1927 // we saw it, and *we* didn't change it, then that implies that the user has changed it,
1928 // so we auto-dismiss the name conflict alert.
1929 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, gNotificationPrefHostLabel
.c
) ||
1930 !SameDomainLabel(m
->p
->usernicelabel
.c
, gNotificationPrefNiceLabel
.c
))
1932 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= m
->p
->userhostlabel
;
1933 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= m
->p
->usernicelabel
;
1934 #ifndef NO_CFUSERNOTIFICATION
1935 // If we're showing a name conflict notification, and the user has manually edited
1936 // the name to remedy the conflict, we should now remove the notification window.
1937 if (gNotificationRLS
) CFUserNotificationCancel(gNotification
);
1938 #endif /* NO_CFUSERNOTIFICATION */
1941 DNSServiceRegistration
*r
;
1942 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1945 ServiceInstance
*si
;
1946 for (si
= r
->regs
; si
; si
= si
->next
)
1948 if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
))
1950 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1951 si
->autorename
= mDNStrue
;
1952 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1953 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1957 udsserver_handle_configchange();
1959 else if (result
== mStatus_GrowCache
)
1961 // Allocate another chunk of cache storage
1962 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1963 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1967 //*************************************************************************************************************
1968 // Add / Update / Remove records from existing Registration
1970 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1971 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1973 // Check client parameter
1975 mStatus err
= mStatus_NoError
;
1976 const char *errormsg
= "Unknown";
1977 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1978 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1979 ServiceInstance
*si
;
1981 (void)unusedserver
; // Unused
1982 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1983 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1985 // Check other parameters
1986 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1987 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1988 else size
= sizeof(RDataBody
);
1991 *reference
= (natural_t
)id
;
1992 for (si
= x
->regs
; si
; si
= si
->next
)
1994 // Allocate memory, and handle failure
1995 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1996 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1998 // Fill in type, length, and data of new record
1999 extra
->r
.resrec
.rrtype
= type
;
2000 extra
->r
.rdatastorage
.MaxRDLength
= size
;
2001 extra
->r
.resrec
.rdlength
= data_len
;
2002 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
2005 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
2006 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
2007 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
2011 freeL("Extra Resource Record", extra
);
2012 errormsg
= "mDNS_AddRecordToService";
2016 extra
->ClientID
= id
;
2019 return mStatus_NoError
;
2022 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
2023 return mStatus_UnknownErr
;
2026 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
2029 if (OldRData
!= &rr
->rdatastorage
)
2030 freeL("Old RData", OldRData
);
2033 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
2035 // Check client parameter
2036 mStatus err
= mStatus_NoError
;
2037 const char *errormsg
= "Unknown";
2038 domainname
*name
= (domainname
*)"";
2040 name
= srs
->RR_SRV
.resrec
.name
;
2042 unsigned int size
= sizeof(RDataBody
);
2043 if (size
< data_len
)
2046 // Allocate memory, and handle failure
2047 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
2048 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
2050 // Fill in new length, and data
2051 newrdata
->MaxRDLength
= size
;
2052 memcpy(&newrdata
->u
, data
, data_len
);
2054 // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
2055 // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
2056 // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
2057 if (rr
->resrec
.rrtype
== kDNSType_TXT
&& data_len
== 0) { data_len
= 1; newrdata
->u
.txt
.c
[0] = 0; }
2060 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
2061 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
2063 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
2066 errormsg
= "mDNS_Update";
2067 freeL("RData", newrdata
);
2070 return(mStatus_NoError
);
2073 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
2077 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2078 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
2080 // Check client parameter
2081 mStatus err
= mStatus_NoError
;
2082 const char *errormsg
= "Unknown";
2083 domainname
*name
= (domainname
*)"";
2084 ServiceInstance
*si
;
2086 (void)unusedserver
; // unused
2087 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2088 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2089 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2090 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2092 // Check other parameters
2093 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
2095 for (si
= x
->regs
; si
; si
= si
->next
)
2097 AuthRecord
*r
= NULL
;
2099 // Find the record we're updating. NULL reference means update the primary TXT record
2100 if (!reference
) r
= &si
->srs
.RR_TXT
;
2103 ExtraResourceRecord
*ptr
;
2104 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
2106 if ((natural_t
)ptr
->ClientID
== reference
)
2107 { r
= &ptr
->r
; break; }
2109 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
2111 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
2112 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
2115 return mStatus_NoError
;
2118 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
2122 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
2124 domainname
*name
= srs
->RR_SRV
.resrec
.name
;
2125 mStatus err
= mStatus_NoError
;
2128 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
2130 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
2131 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
2136 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
2137 natural_t reference
)
2139 // Check client parameter
2140 (void)unusedserver
; // Unused
2141 mStatus err
= mStatus_NoError
;
2142 const char *errormsg
= "Unknown";
2143 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
2144 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
2145 ServiceInstance
*si
;
2147 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
2148 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
2150 for (si
= x
->regs
; si
; si
= si
->next
)
2152 ExtraResourceRecord
*e
;
2153 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
2155 if ((natural_t
)e
->ClientID
== reference
)
2157 err
= RemoveRecord(&si
->srs
, e
, client
);
2161 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
2164 return mStatus_NoError
;
2167 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
2171 //*************************************************************************************************************
2174 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2176 mig_reply_error_t
*request
= msg
;
2177 mig_reply_error_t
*reply
;
2178 mach_msg_return_t mr
;
2180 (void)port
; // Unused
2181 (void)size
; // Unused
2182 (void)info
; // Unused
2184 /* allocate a reply buffer */
2185 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
2187 /* call the MiG server routine */
2188 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
2190 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
2192 if (reply
->RetCode
== MIG_NO_REPLY
)
2195 * This return code is a little tricky -- it appears that the
2196 * demux routine found an error of some sort, but since that
2197 * error would not normally get returned either to the local
2198 * user or the remote one, we pretend it's ok.
2200 CFAllocatorDeallocate(NULL
, reply
);
2205 * destroy any out-of-line data in the request buffer but don't destroy
2206 * the reply port right (since we need that to send an error message).
2208 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2209 mach_msg_destroy(&request
->Head
);
2212 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2214 /* no reply port, so destroy the reply */
2215 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2216 mach_msg_destroy(&reply
->Head
);
2217 CFAllocatorDeallocate(NULL
, reply
);
2224 * We don't want to block indefinitely because the client
2225 * isn't receiving messages from the reply port.
2226 * If we have a send-once right for the reply port, then
2227 * this isn't a concern because the send won't block.
2228 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2229 * To avoid falling off the kernel's fast RPC path unnecessarily,
2230 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2233 options
= MACH_SEND_MSG
;
2234 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2235 options
|= MACH_SEND_TIMEOUT
;
2237 mr
= mach_msg(&reply
->Head
, /* msg */
2238 options
, /* option */
2239 reply
->Head
.msgh_size
, /* send_size */
2241 MACH_PORT_NULL
, /* rcv_name */
2242 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2243 MACH_PORT_NULL
); /* notify */
2245 /* Has a message error occurred? */
2248 case MACH_SEND_INVALID_DEST
:
2249 case MACH_SEND_TIMED_OUT
:
2250 /* the reply can't be delivered, so destroy it */
2251 mach_msg_destroy(&reply
->Head
);
2255 /* Includes success case. */
2259 CFAllocatorDeallocate(NULL
, reply
);
2262 mDNSlocal kern_return_t
registerBootstrapService()
2264 kern_return_t status
;
2265 mach_port_t service_send_port
, service_rcv_port
;
2267 debugf("Registering Bootstrap Service");
2270 * See if our service name is already registered and if we have privilege to check in.
2272 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2273 if (status
== KERN_SUCCESS
)
2276 * If so, we must be a followup instance of an already defined server. In that case,
2277 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2278 * that in case we have to unregister later (which requires the privilege port).
2280 server_priv_port
= bootstrap_port
;
2281 restarting_via_mach_init
= TRUE
;
2283 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2285 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2286 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2287 if (status
!= KERN_SUCCESS
) return status
;
2289 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2290 if (status
!= KERN_SUCCESS
)
2292 mach_port_deallocate(mach_task_self(), server_priv_port
);
2296 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2297 if (status
!= KERN_SUCCESS
)
2299 mach_port_deallocate(mach_task_self(), server_priv_port
);
2300 mach_port_deallocate(mach_task_self(), service_send_port
);
2303 assert(service_send_port
== service_rcv_port
);
2307 * We have no intention of responding to requests on the service port. We are not otherwise
2308 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2309 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2310 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2312 mach_port_destroy(mach_task_self(), service_rcv_port
);
2316 mDNSlocal kern_return_t
destroyBootstrapService()
2318 debugf("Destroying Bootstrap Service");
2319 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2322 mDNSlocal
void ExitCallback(int signal
)
2324 LogMsgIdent(mDNSResponderVersionString
, "stopping");
2326 debugf("ExitCallback");
2327 if (!mDNS_DebugMode
&& !started_via_launchdaemon
&& signal
!= SIGHUP
)
2328 destroyBootstrapService();
2330 debugf("ExitCallback: Aborting MIG clients");
2331 while (DNSServiceDomainEnumerationList
)
2332 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2333 while (DNSServiceBrowserList
)
2334 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2335 while (DNSServiceResolverList
)
2336 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2337 while (DNSServiceRegistrationList
)
2338 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2340 debugf("ExitCallback: mDNS_Close");
2341 mDNS_Close(&mDNSStorage
);
2342 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2346 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2347 mDNSlocal
void HandleSIG(int signal
)
2350 debugf("HandleSIG %d", signal
);
2351 mach_msg_header_t header
;
2352 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2353 header
.msgh_remote_port
= signal_port
;
2354 header
.msgh_local_port
= MACH_PORT_NULL
;
2355 header
.msgh_size
= sizeof(header
);
2356 header
.msgh_id
= signal
;
2357 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2359 LogMsg("HandleSIG %d: mach_msg_send failed", signal
);
2360 if (signal
== SIGHUP
|| signal
== SIGTERM
|| signal
== SIGINT
) exit(-1);
2364 mDNSlocal
void INFOCallback(void)
2366 mDNSs32 utc
= mDNSPlatformUTC();
2367 DNSServiceDomainEnumeration
*e
;
2368 DNSServiceBrowser
*b
;
2369 DNSServiceResolver
*l
;
2370 DNSServiceRegistration
*r
;
2371 NetworkInterfaceInfoOSX
*i
;
2374 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2376 udsserver_info(&mDNSStorage
);
2378 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2379 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2381 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2383 DNSServiceBrowserQuestion
*qptr
;
2384 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2385 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2387 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2388 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2390 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2392 ServiceInstance
*si
;
2393 for (si
= r
->regs
; si
; si
= si
->next
)
2394 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
));
2397 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2400 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
2401 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, utc
- i
->LastSeen
);
2403 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2404 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2405 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2406 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
2407 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
2408 i
->ifinfo
.InterfaceID
,
2409 i
->ifinfo
.Advertise
? "Adv" : " ",
2410 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2414 for (s
= mDNSStorage
.uDNS_info
.Servers
; s
; s
= s
->next
)
2415 LogMsgNoIdent("DNS Server %#a %##s", &s
->addr
, s
->domain
.c
);
2417 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2420 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2422 (void)port
; // Unused
2423 (void)size
; // Unused
2424 (void)info
; // Unused
2425 mach_msg_header_t
*m
= (mach_msg_header_t
*)msg
;
2430 case SIGTERM
: ExitCallback(m
->msgh_id
); break;
2431 case SIGINFO
: INFOCallback(); break;
2432 case SIGUSR1
: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2433 mDNSMacOSXNetworkChanged(&mDNSStorage
); break;
2434 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break;
2438 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
2439 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
2441 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2444 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2445 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2446 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2447 mach_port_t m_port
= CFMachPortGetPort(s_port
);
2448 char *MachServerName
= OSXVers
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2449 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2450 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2451 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2452 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2457 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2459 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2463 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2464 rrcachestorage
, RR_CACHE_SIZE
,
2465 mDNS_Init_AdvertiseLocalAddresses
,
2466 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2468 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2470 gNotificationUserHostLabel
= gNotificationPrefHostLabel
= PlatformStorage
.userhostlabel
;
2471 gNotificationUserNiceLabel
= gNotificationPrefNiceLabel
= PlatformStorage
.usernicelabel
;
2473 client_death_port
= CFMachPortGetPort(d_port
);
2474 signal_port
= CFMachPortGetPort(i_port
);
2476 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
2477 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
2478 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
2482 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2486 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2488 mDNSs32 now
= mDNS_TimeNow(m
);
2490 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2492 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2493 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2494 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2495 // we then systematically lose our own looped-back packets.
2496 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) mDNSMacOSXNetworkChanged(m
);
2498 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2499 mDNSs32 nextevent
= mDNS_Execute(m
);
2501 if (m
->p
->NetworkChanged
)
2502 if (nextevent
- m
->p
->NetworkChanged
> 0)
2503 nextevent
= m
->p
->NetworkChanged
;
2505 // 3. Deliver any waiting browse messages to clients
2506 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2510 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2511 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2512 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2513 DNSServiceBrowser
*x
= b
;
2515 if (x
->results
) // Try to deliver the list of results
2519 DNSServiceBrowserResult
*const r
= x
->results
;
2521 domainname type
, domain
;
2522 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2523 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2524 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2525 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2526 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2527 ConvertDomainNameToCString(&type
, ctype
);
2528 ConvertDomainNameToCString(&domain
, cdom
);
2529 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2530 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2531 // If we failed to send the mach message, try again in one second
2532 if (status
== MACH_SEND_TIMED_OUT
)
2534 if (nextevent
- now
> mDNSPlatformOneSecond
)
2535 nextevent
= now
+ mDNSPlatformOneSecond
;
2540 x
->lastsuccess
= now
;
2541 x
->results
= x
->results
->next
;
2542 freeL("DNSServiceBrowserResult", r
);
2545 // If this client hasn't read a single message in the last 60 seconds, abort it
2546 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2547 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2551 DNSServiceResolver
*l
;
2552 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2553 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2556 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2557 "This places considerable burden on the network.", l
->i
.name
.c
);
2560 if (m
->p
->NotifyUser
)
2562 if (m
->p
->NotifyUser
- now
< 0)
2564 if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2566 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2567 gNotificationPrefNiceLabel
= m
->p
->usernicelabel
= m
->nicelabel
;
2568 RecordUpdatedName(m
, &gNotificationUserNiceLabel
, &gNotificationPrefNiceLabel
, "The name of your computer", "",
2569 CFSTR("To change the name of your computer, open System Preferences and click Sharing. "
2570 "Then type the name in the Computer Name field."));
2571 // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2572 m
->p
->NotifyUser
= 0;
2574 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2576 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2577 gNotificationPrefHostLabel
= m
->p
->userhostlabel
= m
->hostlabel
;
2578 RecordUpdatedName(m
, &gNotificationUserHostLabel
, &gNotificationPrefHostLabel
, "This computer’s local hostname", ".local",
2579 CFSTR("To change the local hostname, open System Preferences and click Sharing. "
2580 "Then click Edit and type the name in the Local Hostname field."));
2582 m
->p
->NotifyUser
= 0;
2585 if (nextevent
- m
->p
->NotifyUser
> 0)
2586 nextevent
= m
->p
->NotifyUser
;
2592 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2596 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2598 // NOTE: To accurately diagnose *why* we're busy, the debugging code here to show needs to mirror the logic in GetNextScheduledEvent
2600 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2601 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2602 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2603 if (m
->NewLocalOnlyQuestions
)
2604 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2605 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2606 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2607 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2608 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2609 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2610 #ifndef UNICAST_DISABLED
2611 if (m
->timenow
- m
->uDNS_info
.nextevent
>= 0)
2612 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m
->timenow
- m
->uDNS_info
.nextevent
);
2614 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2615 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2616 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2617 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2618 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2619 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2620 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2621 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2623 mDNS_Unlock(&mDNSStorage
);
2626 mDNSexport
int main(int argc
, char **argv
)
2629 kern_return_t status
;
2631 for (i
=1; i
<argc
; i
++)
2633 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2634 if (!strcmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2637 signal(SIGHUP
, HandleSIG
); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2638 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2639 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2640 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2641 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2642 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2644 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2645 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2647 registerBootstrapService();
2648 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2649 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2650 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2653 // Avoid unnecessarily duplicating a file descriptor to itself
2654 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2655 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2656 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2657 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2661 // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
2662 // The sooner we do this, the faster the machine will boot.
2663 status
= udsserver_init();
2664 if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; }
2666 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2667 LogMsgIdent(mDNSResponderVersionString
, "starting");
2668 OSXVers
= mDNSMacOSXSystemBuildNumber(NULL
);
2669 status
= mDNSDaemonInitialize();
2671 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2672 // Now that we're finished with anything privileged, switch over to running as "nobody"
2673 const struct passwd
*pw
= getpwnam("nobody");
2677 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2682 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2684 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2686 // This is the main work loop:
2687 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2688 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2689 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2690 // (4) On wakeup we first process *all* events
2691 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2692 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2694 // 1. Before going into a blocking wait call and letting our process to go sleep,
2695 // call mDNSDaemonIdle to allow any deferred work to be completed.
2696 mDNSs32 nextevent
= mDNSDaemonIdle(&mDNSStorage
);
2697 nextevent
= udsserver_idle(nextevent
);
2699 // 2. Work out how long we expect to sleep before the next scheduled task
2700 mDNSs32 ticks
= nextevent
- mDNS_TimeNow(&mDNSStorage
);
2701 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2707 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2709 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2711 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2712 // (a) our next wakeup time, or (b) an event occurs.
2713 // The 'true' parameter makes it return after handling any event that occurs
2714 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2715 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2717 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2719 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2720 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2723 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2727 LogMsg("ERROR: CFRunLoopRun Exiting.");
2728 mDNS_Close(&mDNSStorage
);
2731 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2734 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2738 // uds_daemon.c support routines /////////////////////////////////////////////
2740 // We keep a list of client-supplied event sources in PosixEventSource records
2741 struct CFSocketEventSource
2743 udsEventCallback Callback
;
2746 struct CFSocketEventSource
*Next
;
2748 CFRunLoopSourceRef RLS
;
2750 typedef struct CFSocketEventSource CFSocketEventSource
;
2752 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2754 mDNSlocal
void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
2755 // Called by CFSocket when data appears on socket
2761 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2762 source
->Callback(source
->Context
);
2765 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2766 // Arrange things so that callback is called with context when data appears on fd
2768 CFSocketEventSource
*newSource
;
2769 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2771 if (gEventSources
.LinkOffset
== 0)
2772 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2774 if (fd
>= FD_SETSIZE
|| fd
< 0)
2775 return mStatus_UnsupportedErr
;
2776 if (callback
== NULL
)
2777 return mStatus_BadParamErr
;
2779 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2780 if (NULL
== newSource
)
2781 return mStatus_NoMemoryErr
;
2783 newSource
->Callback
= callback
;
2784 newSource
->Context
= context
;
2787 cfContext
.info
= newSource
;
2788 if ( NULL
!= (newSource
->cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2789 cf_callback
, &cfContext
)) &&
2790 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0)))
2792 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2793 AddToTail(&gEventSources
, newSource
);
2799 CFSocketInvalidate(newSource
->cfs
); // Note: Also closes the underlying socket
2800 CFRelease(newSource
->cfs
);
2802 return mStatus_NoMemoryErr
;
2805 return mStatus_NoError
;
2808 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2809 // Reverse what was done in udsSupportAddFDToEventLoop().
2811 CFSocketEventSource
*iSource
;
2813 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2815 if (fd
== iSource
->fd
)
2817 RemoveFromList(&gEventSources
, iSource
);
2818 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2819 CFRunLoopSourceInvalidate(iSource
->RLS
);
2820 CFRelease(iSource
->RLS
);
2821 CFSocketInvalidate(iSource
->cfs
); // Note: Also closes the underlying socket
2822 CFRelease(iSource
->cfs
);
2824 return mStatus_NoError
;
2827 return mStatus_NoSuchNameErr
;
2830 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2831 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2832 asm(".desc ___crashreporter_info__, 0x10");
2834 // For convenience when using the "strings" command, this is the last thing in the file
2835 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";