2  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24  * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion 
  25  * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>, 
  26  * but for the sake of brevity here I will say just this: Curly braces are not syntactially 
  27  * part of an "if" statement; they are the beginning and ending markers of a compound statement; 
  28  * therefore common sense dictates that if they are part of a compound statement then they 
  29  * should be indented to the same level as everything else in that compound statement. 
  30  * Indenting curly braces at the same level as the "if" implies that curly braces are 
  31  * part of the "if", which is false. (This is as misleading as people who write "char* x,y;" 
  32  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't 
  33  * understand why variable y is not of type "char*" just proves the point that poor code 
  34  * layout leads people to unfortunate misunderstandings about how the C language really works.) 
  36     Change History (most recent first): 
  39 Revision 1.257  2005/03/28 19:28:55  cheshire 
  40 Fix minor typos in LogOperation() messages 
  42 Revision 1.256  2005/03/17 22:01:22  cheshire 
  43 Tidy up alignment of lines to make code more readable 
  45 Revision 1.255  2005/03/09 00:48:43  cheshire 
  46 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep 
  47 Move "m->p->NetworkChanged = 0;" line from caller to callee 
  49 Revision 1.254  2005/03/03 04:34:19  cheshire 
  50 <rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy 
  52 Revision 1.253  2005/03/03 03:55:09  cheshire 
  53 <rdar://problem/3862944> Name collision notifications should be localized 
  55 Revision 1.252  2005/02/23 02:29:17  cheshire 
  56 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed 
  57 Minor refinements, better variable names, improved comments 
  59 Revision 1.251  2005/02/21 21:31:24  ksekar 
  60 <rdar://problem/4015162> changed LogMsg to debugf 
  62 Revision 1.250  2005/02/19 01:25:04  cheshire 
  63 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed 
  66 Revision 1.249  2005/02/19 00:28:45  cheshire 
  67 <rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed 
  69 Revision 1.248  2005/02/19 00:18:34  cheshire 
  70 Confusing variable name -- alertMessage should be called alertHeader 
  72 Revision 1.247  2005/02/15 02:13:49  cheshire 
  73 If we did registerBootstrapService() when starting, then we must do 
  74 destroyBootstrapService() before exiting, or Mach init will keep restarting us. 
  76 Revision 1.246  2005/02/03 00:44:37  cheshire 
  77 <rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL 
  79 Revision 1.245  2005/02/01 19:56:47  ksekar 
  80 Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording 
  82 Revision 1.244  2005/01/28 00:34:49  cheshire 
  83 Turn off "Starting time value" log message 
  85 Revision 1.243  2005/01/27 17:46:58  cheshire 
  86 Added comment about CFSocketInvalidate closing the underlying socket 
  88 Revision 1.242  2005/01/27 00:10:58  cheshire 
  89 <rdar://problem/3967867> Name change log messages every time machine boots 
  91 Revision 1.241  2005/01/25 17:28:06  ksekar 
  92 <rdar://problem/3971467> Should not return "local" twice for domain enumeration 
  94 Revision 1.240  2005/01/21 02:39:18  cheshire 
  95 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain() 
  97 Revision 1.239  2005/01/20 00:25:01  cheshire 
  98 Improve validatelists() log message generation 
 100 Revision 1.238  2005/01/19 19:15:35  ksekar 
 101 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer 
 103 Revision 1.237  2005/01/19 03:33:09  cheshire 
 104 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets 
 106 Revision 1.236  2005/01/19 03:16:38  cheshire 
 107 <rdar://problem/3961051> CPU Spin in mDNSResponder 
 108 Improve detail of "Task Scheduling Error" diagnostic messages 
 110 Revision 1.235  2005/01/15 00:56:41  ksekar 
 111 <rdar://problem/3954575> Unicast services don't disappear when logging 
 114 Revision 1.234  2005/01/10 03:42:30  ksekar 
 117 Revision 1.233  2004/12/18 00:53:46  cheshire 
 118 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0 
 120 Revision 1.232  2004/12/17 23:37:48  cheshire 
 121 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association 
 122 (and other repetitive configuration changes) 
 124 Revision 1.231  2004/12/17 04:13:38  cheshire 
 125 Removed debugging check 
 127 Revision 1.230  2004/12/17 04:09:30  cheshire 
 128 <rdar://problem/3191011> Switch mDNSResponder to launchd 
 130 Revision 1.229  2004/12/16 21:51:36  cheshire 
 131 Remove some startup messages 
 133 Revision 1.228  2004/12/16 20:13:01  cheshire 
 134 <rdar://problem/3324626> Cache memory management improvements 
 136 Revision 1.227  2004/12/10 13:52:57  cheshire 
 137 <rdar://problem/3909995> Turn off SIGPIPE signals 
 139 Revision 1.226  2004/12/10 05:27:26  cheshire 
 140 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine 
 142 Revision 1.225  2004/12/10 04:28:29  cheshire 
 143 <rdar://problem/3914406> User not notified of name changes for services using new UDS API 
 145 Revision 1.224  2004/12/10 00:41:05  cheshire 
 146 Adjust alignment of log messages 
 148 Revision 1.223  2004/12/07 20:42:34  cheshire 
 149 Add explicit context parameter to mDNS_RemoveRecordFromService() 
 151 Revision 1.222  2004/12/06 21:15:23  ksekar 
 152 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations 
 154 Revision 1.221  2004/11/30 03:24:04  cheshire 
 155 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized 
 157 Revision 1.220  2004/11/29 23:34:31  cheshire 
 158 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero 
 159 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function 
 160 only nudges the time value to 1 if the interval calculation happens to result in the value zero. 
 162 Revision 1.219  2004/11/25 01:00:56  cheshire 
 163 Checkin 1.217 not necessary 
 165 Revision 1.218  2004/11/24 20:27:19  cheshire 
 166 Add missing "err" parameter in LogMsg() call 
 168 Revision 1.217  2004/11/24 17:55:01  ksekar 
 169 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal 
 171 Revision 1.216  2004/11/24 00:10:44  cheshire 
 172 <rdar://problem/3869241> For unicast operations, verify that service types are legal 
 174 Revision 1.215  2004/11/23 22:33:01  cheshire 
 175 <rdar://problem/3654910> Remove temporary workaround code for iChat 
 177 Revision 1.214  2004/11/23 22:13:59  cheshire 
 178 <rdar://problem/3886293> Subtype advertising broken for Mach API 
 180 Revision 1.213  2004/11/23 06:12:55  cheshire 
 181 <rdar://problem/3871405> Update wording for name conflict dialogs 
 183 Revision 1.212  2004/11/23 05:15:37  cheshire 
 184 <rdar://problem/3875830> Computer Name in use message garbled 
 186 Revision 1.211  2004/11/23 05:00:41  cheshire 
 187 <rdar://problem/3874629> Name conflict log message should not have ".local" appended 
 189 Revision 1.210  2004/11/03 03:45:17  cheshire 
 190 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions 
 192 Revision 1.209  2004/11/03 02:25:50  cheshire 
 193 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict 
 195 Revision 1.208  2004/11/03 01:54:14  cheshire 
 196 Update debugging messages 
 198 Revision 1.207  2004/11/02 23:58:19  cheshire 
 199 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions 
 201 Revision 1.206  2004/10/28 02:40:47  cheshire 
 202 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event) 
 204 Revision 1.205  2004/10/28 02:21:01  cheshire 
 205 <rdar://problem/3856500> Improve mDNSResponder signal handling 
 206 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9) 
 207 Added SIGUSR1 to simulate a network change notification from System Configuration Framework 
 209 Revision 1.204  2004/10/27 01:57:21  cheshire 
 210 Add check of  m->p->InterfaceList 
 212 Revision 1.203  2004/10/26 04:31:44  cheshire 
 213 Rename CountSubTypes() as ChopSubTypes() 
 215 Revision 1.202  2004/10/26 01:29:18  cheshire 
 216 Use "#if 0" instead of commenting out code 
 218 Revision 1.201  2004/10/25 21:41:39  ksekar 
 219 <rdar://problem/3852958> wide-area name conflicts can cause crash 
 221 Revision 1.200  2004/10/22 01:03:55  cheshire 
 222 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data 
 223 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails 
 225 Revision 1.199  2004/10/19 21:33:19  cheshire 
 226 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API 
 227 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name 
 228 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want 
 230 Revision 1.198  2004/10/15 23:00:18  ksekar 
 231 <rdar://problem/3799242> Need to update LLQs on location changes 
 233 Revision 1.197  2004/10/12 23:38:59  ksekar 
 234 <rdar://problem/3837065> remove unnecessary log message 
 236 Revision 1.196  2004/10/04 05:56:04  cheshire 
 237 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes 
 239 Revision 1.195  2004/09/30 00:24:59  ksekar 
 240 <rdar://problem/3695802> Dynamically update default registration domains on config change 
 242 Revision 1.194  2004/09/26 23:20:35  ksekar 
 243 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains 
 245 Revision 1.193  2004/09/23 23:35:27  cheshire 
 248 Revision 1.192  2004/09/21 23:40:12  ksekar 
 249 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure 
 251 Revision 1.191  2004/09/21 21:05:12  cheshire 
 252 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c, 
 253 into mDNSShared/uds_daemon.c 
 255 Revision 1.190  2004/09/21 19:51:15  cheshire 
 256 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c 
 258 Revision 1.189  2004/09/21 18:17:23  cheshire 
 259 <rdar://problem/3785400> Add version info to mDNSResponder 
 261 Revision 1.188  2004/09/20 21:45:27  ksekar 
 264 Revision 1.187  2004/09/17 01:08:52  cheshire 
 265 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h 
 266   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces 
 267   declared in that file are ONLY appropriate to single-address-space embedded applications. 
 268   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. 
 270 Revision 1.186  2004/09/16 00:24:49  cheshire 
 271 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow() 
 273 Revision 1.185  2004/08/25 02:01:45  cheshire 
 274 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update 
 276 Revision 1.184  2004/08/19 19:04:12  ksekar 
 277 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service 
 279 Revision 1.183  2004/08/14 03:22:42  cheshire 
 280 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue 
 281 Add GetUserSpecifiedDDNSName() routine 
 282 Convert ServiceRegDomain to domainname instead of C string 
 283 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs 
 285 Revision 1.182  2004/08/13 23:57:59  cheshire 
 286 Get rid of non-portable "_UNUSED" 
 288 Revision 1.181  2004/08/11 02:02:26  cheshire 
 289 Remove "mDNS *globalInstance" parameter from udsserver_init(); 
 290 Move CheckForDuplicateRegistrations to uds_daemon.c 
 292 Revision 1.180  2004/07/13 21:24:25  rpantos 
 293 Fix for <rdar://problem/3701120>. 
 295 Revision 1.179  2004/06/19 00:02:54  cheshire 
 296 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain 
 298 Revision 1.178  2004/06/18 19:10:00  cheshire 
 299 <rdar://problem/3588761> Current method of doing subtypes causes name collisions 
 301 Revision 1.177  2004/06/16 23:14:46  ksekar 
 302 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain 
 304 Revision 1.176  2004/06/11 20:27:42  cheshire 
 305 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms 
 307 Revision 1.175  2004/06/10 20:23:21  cheshire 
 308 Also list interfaces in SIGINFO output 
 310 Revision 1.174  2004/06/08 18:54:48  ksekar 
 311 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility 
 313 Revision 1.173  2004/06/08 17:35:12  cheshire 
 314 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU 
 316 Revision 1.172  2004/06/05 00:04:26  cheshire 
 317 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration 
 319 Revision 1.171  2004/06/04 08:58:30  ksekar 
 320 <rdar://problem/3668624>: Keychain integration for secure dynamic update 
 322 Revision 1.170  2004/05/30 20:01:50  ksekar 
 323 <rdar://problem/3668635>: wide-area default registrations should be in 
 324 .local too - fixed service registration when clients pass an explicit 
 325 domain (broken by previous checkin) 
 327 Revision 1.169  2004/05/30 01:30:16  ksekar 
 328 <rdar://problem/3668635>: wide-area default registrations should be in 
 331 Revision 1.168  2004/05/18 23:51:26  cheshire 
 332 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers 
 334 Revision 1.167  2004/05/14 16:39:47  ksekar 
 335 Browse for iChat locally for now. 
 337 Revision 1.166  2004/05/13 21:33:52  ksekar 
 338 Clean up non-local registration control via config file.  Force iChat 
 339 registrations to be local for now. 
 341 Revision 1.165  2004/05/13 04:54:20  ksekar 
 342 Unified list copy/free code.  Added symetric list for 
 344 Revision 1.164  2004/05/12 22:03:08  ksekar 
 345 Made GetSearchDomainList a true platform-layer call (declaration moved 
 346 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local" 
 347 only on non-OSX platforms.  Changed call to return a copy of the list 
 348 to avoid shared memory issues.  Added a routine to free the list. 
 350 Revision 1.163  2004/05/12 02:03:25  ksekar 
 351 Non-local domains will only be browsed by default, and show up in 
 352 _browse domain enumeration, if they contain an _browse._dns-sd ptr record. 
 354 Revision 1.162  2004/04/14 23:09:29  ksekar 
 355 Support for TSIG signed dynamic updates. 
 357 Revision 1.161  2004/04/07 01:20:04  cheshire 
 358 Hash slot value should be unsigned 
 360 Revision 1.160  2004/04/06 19:51:24  cheshire 
 361 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist. 
 362 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist. 
 364 Revision 1.159  2004/04/03 01:36:55  cheshire 
 365 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist. 
 366 If "nobody" user doesn't exist, log a message and continue as "root" 
 368 Revision 1.158  2004/04/02 21:39:05  cheshire 
 369 Fix errors in comments 
 371 Revision 1.157  2004/03/19 18:49:10  ksekar 
 372 Increased size check in freeL() to account for LargeCacheRecord 
 373 structs larger than 8k 
 375 Revision 1.156  2004/03/19 18:19:19  ksekar 
 376 Fixed daemon.c to compile with malloc debugging turned on. 
 378 Revision 1.155  2004/03/13 01:57:34  ksekar 
 379 <rdar://problem/3192546>: DynDNS: Dynamic update of service records 
 381 Revision 1.154  2004/03/12 08:42:47  cheshire 
 382 <rdar://problem/3548256>: Should not allow empty string for resolve domain 
 384 Revision 1.153  2004/03/12 08:08:51  cheshire 
 387 Revision 1.152  2004/02/05 19:39:29  cheshire 
 388 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c, 
 389 so that all platforms get this functionality 
 391 Revision 1.151  2004/02/03 22:35:34  cheshire 
 392 <rdar://problem/3548256>: Should not allow empty string for resolve domain 
 394 Revision 1.150  2004/01/28 21:14:23  cheshire 
 395 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode) 
 397 Revision 1.149  2004/01/28 02:30:08  ksekar 
 398 Added default Search Domains to unicast browsing, controlled via 
 399 Networking sharing prefs pane.  Stopped sending unicast messages on 
 400 every interface.  Fixed unicast resolving via mach-port API. 
 402 Revision 1.148  2004/01/25 00:03:20  cheshire 
 403 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro 
 405 Revision 1.147  2004/01/19 19:51:46  cheshire 
 406 Fix compiler error (mixed declarations and code) on some versions of Linux 
 408 Revision 1.146  2003/12/08 21:00:46  rpantos 
 409 Changes to support mDNSResponder on Linux. 
 411 Revision 1.145  2003/12/05 22:08:07  cheshire 
 412 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1) 
 414 Revision 1.144  2003/11/19 23:21:08  ksekar 
 415 <rdar://problem/3486646>: config change handler not called for dns-sd services 
 417 Revision 1.143  2003/11/14 21:18:32  cheshire 
 418 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder 
 419 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers. 
 421 Revision 1.142  2003/11/08 22:18:29  cheshire 
 422 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message 
 424 Revision 1.141  2003/11/07 02:30:57  cheshire 
 425 Also check per-slot cache use counts in SIGINFO state log 
 427 Revision 1.140  2003/10/21 19:58:26  cheshire 
 428 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records) 
 430 Revision 1.139  2003/10/21 00:10:18  rpantos 
 431 <rdar://problem/3409401>: mDNSResponder should not run as root 
 433 Revision 1.138  2003/10/07 20:16:58  cheshire 
 434 Shorten syslog message a bit 
 436 Revision 1.137  2003/09/23 02:12:43  cheshire 
 437 Also include port number in list of services registered via new UDS API 
 439 Revision 1.136  2003/09/23 02:07:25  cheshire 
 440 Include port number in DNSServiceRegistration START/STOP messages 
 442 Revision 1.135  2003/09/23 01:34:02  cheshire 
 443 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations 
 445 Revision 1.134  2003/08/21 20:01:37  cheshire 
 446 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog 
 448 Revision 1.133  2003/08/20 23:39:31  cheshire 
 449 <rdar://problem/3344098> Review syslog messages, and remove as appropriate 
 451 Revision 1.132  2003/08/20 01:44:56  cheshire 
 452 Fix errors in LogOperation() calls (only used for debugging) 
 454 Revision 1.131  2003/08/19 05:39:43  cheshire 
 455 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord 
 457 Revision 1.130  2003/08/16 03:39:01  cheshire 
 458 <rdar://problem/3338440> InterfaceID -1 indicates "local only" 
 460 Revision 1.129  2003/08/15 20:16:03  cheshire 
 461 <rdar://problem/3366590> mDNSResponder takes too much RPRVT 
 462 We want to avoid touching the rdata pages, so we don't page them in. 
 463 1. RDLength was stored with the rdata, which meant touching the page just to find the length. 
 464    Moved this from the RData to the ResourceRecord object. 
 465 2. To avoid unnecessarily touching the rdata just to compare it, 
 466    compute a hash of the rdata and store the hash in the ResourceRecord object. 
 468 Revision 1.128  2003/08/14 19:30:36  cheshire 
 469 <rdar://problem/3378473> Include list of cache records in SIGINFO output 
 471 Revision 1.127  2003/08/14 02:18:21  cheshire 
 472 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord 
 474 Revision 1.126  2003/08/12 19:56:25  cheshire 
 477 Revision 1.125  2003/08/08 18:36:04  cheshire 
 478 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug 
 480 Revision 1.124  2003/07/25 18:28:23  cheshire 
 481 Minor fix to error messages in syslog: Display string parameters with quotes 
 483 Revision 1.123  2003/07/23 17:45:28  cheshire 
 484 <rdar://problem/3339388> mDNSResponder leaks a bit 
 485 Don't allocate memory for the reply until after we've verified that the reply is valid 
 487 Revision 1.122  2003/07/23 00:00:04  cheshire 
 490 Revision 1.121  2003/07/20 03:38:51  ksekar 
 491 <rdar://problem/3320722> Completed support for Unix-domain socket based API. 
 493 Revision 1.120  2003/07/18 00:30:00  cheshire 
 494 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead 
 496 Revision 1.119  2003/07/17 19:08:58  cheshire 
 497 <rdar://problem/3332153> Remove calls to enable obsolete UDS code 
 499 Revision 1.118  2003/07/15 21:12:28  cheshire 
 500 Added extra debugging checks in validatelists() (not used in final shipping version) 
 502 Revision 1.117  2003/07/15 01:55:15  cheshire 
 503 <rdar://problem/3315777> Need to implement service registration with subtypes 
 505 Revision 1.116  2003/07/02 21:19:51  cheshire 
 506 <rdar://problem/3313413> Update copyright notices, etc., in source code comments 
 508 Revision 1.115  2003/07/02 02:41:24  cheshire 
 509 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed 
 511 Revision 1.114  2003/07/01 21:10:20  cheshire 
 512 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112 
 514 Revision 1.113  2003/06/28 17:27:43  vlubet 
 515 <rdar://problem/3221246> Redirect standard input, standard output, and 
 516 standard error file descriptors to /dev/null just like any other 
 519 Revision 1.112  2003/06/25 23:42:19  ksekar 
 520 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875) 
 521 Reviewed by: Stuart Cheshire 
 522 Added files necessary to implement Unix domain sockets based enhanced 
 523 DNS-SD APIs, and integrated with existing Mach-port based daemon. 
 525 Revision 1.111  2003/06/11 01:02:43  cheshire 
 526 <rdar://problem/3287858> mDNSResponder binary compatibility 
 527 Make single binary that can run on both Jaguar and Panther. 
 529 Revision 1.110  2003/06/10 01:14:11  cheshire 
 530 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call 
 532 Revision 1.109  2003/06/06 19:53:43  cheshire 
 533 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass 
 534 (Global search-and-replace; no functional change to code execution.) 
 536 Revision 1.108  2003/06/06 14:08:06  cheshire 
 537 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle() 
 539 Revision 1.107  2003/05/29 05:44:55  cheshire 
 540 Minor fixes to log messages 
 542 Revision 1.106  2003/05/27 18:30:55  cheshire 
 543 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state 
 544 Dean Reece suggested SIGINFO is more appropriate than SIGHUP 
 546 Revision 1.105  2003/05/26 03:21:29  cheshire 
 547 Tidy up address structure naming: 
 548 mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr) 
 549 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 
 550 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 
 552 Revision 1.104  2003/05/26 00:42:06  cheshire 
 553 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets 
 555 Revision 1.103  2003/05/23 23:07:44  cheshire 
 556 <rdar://problem/3268199> Must not write to stderr when running as daemon 
 558 Revision 1.102  2003/05/22 01:32:31  cheshire 
 559 Fix typo in Log message format string 
 561 Revision 1.101  2003/05/22 00:26:55  cheshire 
 562 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup 
 563 Modify error message to explain that this is technically legal, but may indicate a bug. 
 565 Revision 1.100  2003/05/21 21:02:24  ksekar 
 566 <rdar://problem/3247035>: Service should be prefixed 
 567 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main 
 568 Mach message port to "com.apple.mDNSResponder. 
 570 Revision 1.99  2003/05/21 17:33:49  cheshire 
 571 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.) 
 573 Revision 1.98  2003/05/20 00:33:07  cheshire 
 574 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state 
 575 SIGHUP now writes state summary to syslog 
 577 Revision 1.97  2003/05/08 00:19:08  cheshire 
 578 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places 
 580 Revision 1.96  2003/05/07 22:10:46  cheshire 
 581 <rdar://problem/3250330> Add a few more error logging messages 
 583 Revision 1.95  2003/05/07 19:20:17  cheshire 
 584 <rdar://problem/3251391> Add version number to mDNSResponder builds 
 586 Revision 1.94  2003/05/07 00:28:18  cheshire 
 587 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients 
 589 Revision 1.93  2003/05/06 00:00:49  cheshire 
 590 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions 
 592 Revision 1.92  2003/04/04 20:38:57  cheshire 
 597 #include <mach/mach.h> 
 598 #include <mach/mach_error.h> 
 599 #include <servers/bootstrap.h> 
 600 #include <sys/types.h> 
 605 #include <SystemConfiguration/SCPreferencesSetSpecific.h> 
 607 #include "DNSServiceDiscoveryRequestServer.h" 
 608 #include "DNSServiceDiscoveryReply.h" 
 610 #include "DNSCommon.h" 
 611 #include "mDNSMacOSX.h"                         // Defines the specific types needed to run mDNS on this platform 
 613 #include "uds_daemon.h"                         // Interface to the server side implementation of dns_sd.h 
 615 #include "GenLinkedList.h" 
 617 #include <DNSServiceDiscovery/DNSServiceDiscovery.h> 
 619 //************************************************************************************************************* 
 622 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion 
 623 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" 
 624 // To expand "version" to its value before making the string, use STRINGIFY(version) instead 
 625 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s 
 626 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) 
 628 //************************************************************************************************************* 
 631 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain 
 632 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off 
 633 static mDNS_PlatformSupport PlatformStorage
; 
 635 // Start off with a default cache of 16K (about 100 records) 
 636 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord)) 
 637 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
]; 
 639 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart"; 
 640 static mach_port_t client_death_port 
= MACH_PORT_NULL
; 
 641 static mach_port_t signal_port       
= MACH_PORT_NULL
; 
 642 static mach_port_t server_priv_port  
= MACH_PORT_NULL
; 
 644 // mDNS Mach Message Timeout, in milliseconds. 
 645 // We need this to be short enough that we don't deadlock the mDNSResponder if a client 
 646 // fails to service its mach message queue, but long enough to give a well-written 
 647 // client a chance to service its mach message queue without getting cut off. 
 648 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give 
 649 // even extra-slow clients a fair chance before we cut them off. 
 650 #define MDNS_MM_TIMEOUT 250 
 652 static int restarting_via_mach_init 
= 0; 
 653 static int started_via_launchdaemon 
= 0; 
 657 //************************************************************************************************************* 
 658 // Active client list structures 
 660 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
; 
 661 struct DNSServiceDomainEnumeration_struct
 
 663         DNSServiceDomainEnumeration 
*next
; 
 664         mach_port_t ClientMachPort
; 
 665         DNSQuestion dom
;        // Question asking for domains 
 666         DNSQuestion def
;        // Question asking for default domain 
 669 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
; 
 670 struct DNSServiceBrowserResult_struct
 
 672         DNSServiceBrowserResult 
*next
; 
 677 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
; 
 679 typedef struct DNSServiceBrowserQuestion
 
 681         struct DNSServiceBrowserQuestion 
*next
; 
 684         } DNSServiceBrowserQuestion
; 
 686 struct DNSServiceBrowser_struct
 
 688         DNSServiceBrowser 
*next
; 
 689         mach_port_t ClientMachPort
; 
 690         DNSServiceBrowserQuestion 
*qlist
; 
 691         DNSServiceBrowserResult 
*results
; 
 693     mDNSBool DefaultDomain
;                // was the browse started on an explicit domain? 
 694     domainname type
;                       //  registration type  
 697 typedef struct DNSServiceResolver_struct DNSServiceResolver
; 
 698 struct DNSServiceResolver_struct
 
 700         DNSServiceResolver 
*next
; 
 701         mach_port_t ClientMachPort
; 
 707 // A single registered service: ServiceRecordSet + bookkeeping 
 708 // Note that we duplicate some fields from parent DNSServiceRegistration object 
 709 // to facilitate cleanup, when instances and parent may be deallocated at different times. 
 710 typedef struct ServiceInstance
 
 712     struct ServiceInstance 
*next
; 
 713         mach_port_t ClientMachPort
; 
 714     mDNSBool autoname
;                  // Set if this name is tied to the Computer Name 
 715     mDNSBool autorename
;                // Set if we just got a name conflict and now need to automatically pick a new name 
 718     ServiceRecordSet srs
; 
 719         // Don't add any fields after ServiceRecordSet. 
 720         // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object 
 723 // A client-created service.  May reference several ServiceInstance objects if default 
 724 // settings cause registration in multiple domains. 
 725 typedef struct DNSServiceRegistration
 
 727     struct DNSServiceRegistration 
*next
; 
 728         mach_port_t ClientMachPort
; 
 729     mDNSBool DefaultDomain
; 
 733     char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes 
 734     domainlabel name
;  // used only if autoname is false  
 737     unsigned char txtinfo
[1024]; 
 740     ServiceInstance 
*regs
; 
 741         } DNSServiceRegistration
; 
 743 static DNSServiceDomainEnumeration 
*DNSServiceDomainEnumerationList 
= NULL
; 
 744 static DNSServiceBrowser           
*DNSServiceBrowserList           
= NULL
; 
 745 static DNSServiceResolver          
*DNSServiceResolverList          
= NULL
; 
 746 static DNSServiceRegistration      
*DNSServiceRegistrationList      
= NULL
; 
 748 //************************************************************************************************************* 
 749 // General Utility Functions 
 751 #if MACOSX_MDNS_MALLOC_DEBUGGING 
 753 char _malloc_options
[] = "AXZ"; 
 755 mDNSlocal 
void validatelists(mDNS 
*const m
) 
 757         DNSServiceDomainEnumeration 
*e
; 
 758         DNSServiceBrowser           
*b
; 
 759         DNSServiceResolver          
*l
; 
 760         DNSServiceRegistration      
*r
; 
 766         NetworkInterfaceInfoOSX     
*i
; 
 768         for (e 
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
) 
 769                 if (e
->ClientMachPort 
== 0 || e
->ClientMachPort 
== (mach_port_t
)~0) 
 770                         LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
); 
 772         for (b 
= DNSServiceBrowserList
; b
; b
=b
->next
) 
 773                 if (b
->ClientMachPort 
== 0 || b
->ClientMachPort 
== (mach_port_t
)~0) 
 774                         LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
); 
 776         for (l 
= DNSServiceResolverList
; l
; l
=l
->next
) 
 777                 if (l
->ClientMachPort 
== 0 || l
->ClientMachPort 
== (mach_port_t
)~0) 
 778                         LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
); 
 780         for (r 
= DNSServiceRegistrationList
; r
; r
=r
->next
) 
 781                 if (r
->ClientMachPort 
== 0 || r
->ClientMachPort 
== (mach_port_t
)~0) 
 782                         LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
); 
 784         for (rr 
= m
->ResourceRecords
; rr
; rr
=rr
->next
) 
 786                 if (rr
->resrec
.RecordType 
== 0 || rr
->resrec
.RecordType 
== 0xFF) 
 787                         LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
); 
 788                 if (rr
->resrec
.name 
!= &rr
->namestorage
) 
 789                         LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s", 
 790                                 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
); 
 793         for (rr 
= m
->DuplicateRecords
; rr
; rr
=rr
->next
) 
 794                 if (rr
->resrec
.RecordType 
== 0 || rr
->resrec
.RecordType 
== 0xFF) 
 795                         LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
); 
 797         for (q 
= m
->Questions
; q
; q
=q
->next
) 
 798                 if (q
->ThisQInterval 
== (mDNSs32
)~0) 
 799                         LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
); 
 801         FORALL_CACHERECORDS(slot
, cg
, cr
) 
 802                 if (cr
->resrec
.RecordType 
== 0 || cr
->resrec
.RecordType 
== 0xFF) 
 803                         LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->resrec
.RecordType
); 
 805         for (i 
= m
->p
->InterfaceList
; i
; i 
= i
->next
) 
 807                         LogMsg("!!!! InterfaceList: %p is garbage !!!!", i
); 
 810 void *mallocL(char *msg
, unsigned int size
) 
 812         unsigned long *mem 
= malloc(size
+8); 
 815                 LogMsg("malloc( %s : %d ) failed", msg
, size
); 
 820                 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]); 
 823                 //bzero(&mem[2], size); 
 824                 memset(&mem
[2], 0xFF, size
); 
 825                 validatelists(&mDNSStorage
); 
 830 void freeL(char *msg
, void *x
) 
 833                 LogMsg("free( %s @ NULL )!", msg
); 
 836                 unsigned long *mem 
= ((unsigned long *)x
) - 2; 
 837                 if (mem
[0] != 0xDEAD1234) 
 838                         { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; } 
 840                         { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; } 
 841                 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]); 
 842                 //bzero(mem, mem[1]+8); 
 843                 memset(mem
, 0xFF, mem
[1]+8); 
 844                 validatelists(&mDNSStorage
); 
 851 //************************************************************************************************************* 
 852 // Client Death Detection 
 854 mDNSlocal 
void FreeServiceInstance(ServiceInstance 
*x
) 
 856         ServiceRecordSet 
*s 
= &x
->srs
; 
 857         ExtraResourceRecord 
*e 
= x
->srs
.Extras
, *tmp
; 
 861                 e
->r
.RecordContext 
= e
; 
 864                 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
); 
 867         if (s
->RR_TXT
.resrec
.rdata 
!= &s
->RR_TXT
.rdatastorage
) 
 868                         freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
); 
 870         if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
); 
 871         freeL("ServiceInstance", x
); 
 874 // AbortClient finds whatever client is identified by the given Mach port, 
 875 // stops whatever operation that client was doing, and frees its memory. 
 876 // In the case of a service registration, the actual freeing may be deferred 
 877 // until we get the mStatus_MemFree message, if necessary 
 878 mDNSlocal 
void AbortClient(mach_port_t ClientMachPort
, void *m
) 
 880         DNSServiceDomainEnumeration 
**e 
= &DNSServiceDomainEnumerationList
; 
 881         DNSServiceBrowser           
**b 
= &DNSServiceBrowserList
; 
 882         DNSServiceResolver          
**l 
= &DNSServiceResolverList
; 
 883         DNSServiceRegistration      
**r 
= &DNSServiceRegistrationList
; 
 885         while (*e 
&& (*e
)->ClientMachPort 
!= ClientMachPort
) e 
= &(*e
)->next
; 
 888                 DNSServiceDomainEnumeration 
*x 
= *e
; 
 891                         LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
); 
 892                 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
); 
 893                 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
); 
 894                 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
); 
 895                 freeL("DNSServiceDomainEnumeration", x
); 
 899         while (*b 
&& (*b
)->ClientMachPort 
!= ClientMachPort
) b 
= &(*b
)->next
; 
 902                 DNSServiceBrowser 
*x 
= *b
; 
 903                 DNSServiceBrowserQuestion 
*freePtr
, *qptr 
= x
->qlist
; 
 908                                 LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
); 
 909                         else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
); 
 910                         mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
); 
 913                         freeL("DNSServiceBrowserQuestion", freePtr
); 
 917                         DNSServiceBrowserResult 
*r 
= x
->results
; 
 918                         x
->results 
= x
->results
->next
; 
 919                         freeL("DNSServiceBrowserResult", r
); 
 921                 freeL("DNSServiceBrowser", x
); 
 925         while (*l 
&& (*l
)->ClientMachPort 
!= ClientMachPort
) l 
= &(*l
)->next
; 
 928                 DNSServiceResolver 
*x 
= *l
; 
 931                         LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
); 
 932                 else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort
, x
->i
.name
.c
); 
 933                 mDNS_StopResolveService(&mDNSStorage
, &x
->q
); 
 934                 freeL("DNSServiceResolver", x
); 
 938         while (*r 
&& (*r
)->ClientMachPort 
!= ClientMachPort
) r 
= &(*r
)->next
; 
 941                 ServiceInstance 
*si 
= NULL
; 
 942                 DNSServiceRegistration 
*x 
= *r
; 
 948                         ServiceInstance 
*instance 
= si
; 
 950                         instance
->autorename 
= mDNSfalse
; 
 951                         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
);                        
 952                         else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
)); 
 954                         // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list, 
 955                         // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory. 
 956                         // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from 
 957                         // the list, so we should go ahead and free the memory right now 
 958                         if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer 
 961                 freeL("DNSServiceRegistration", x
); 
 965         LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
); 
 968 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M)) 
 970 mDNSlocal 
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
) 
 972         DNSServiceDomainEnumeration 
*e 
= DNSServiceDomainEnumerationList
; 
 973         DNSServiceBrowser           
*b 
= DNSServiceBrowserList
; 
 974         DNSServiceResolver          
*l 
= DNSServiceResolverList
; 
 975         DNSServiceRegistration      
*r 
= DNSServiceRegistrationList
; 
 976         DNSServiceBrowserQuestion   
*qptr
; 
 978         while (e 
&& e
->ClientMachPort 
!= c
) e 
= e
->next
; 
 979         while (b 
&& b
->ClientMachPort 
!= c
) b 
= b
->next
; 
 980         while (l 
&& l
->ClientMachPort 
!= c
) l 
= l
->next
; 
 981         while (r 
&& r
->ClientMachPort 
!= c
) r 
= r
->next
; 
 983         if      (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s",                   c
, e
->dom
.qname
.c
,                reason
, msg
); 
 986                         for (qptr 
= b
->qlist
; qptr
; qptr 
= qptr
->next
) 
 987                                 LogMsg("%5d: Browser(%##s) %s%s",                             c
, qptr
->q
.qname
.c
,               reason
, msg
); 
 989         else if (l
) LogMsg("%5d: Resolver(%##s) %s%s",                            c
, l
->i
.name
.c
,                   reason
, msg
); 
 993                         for (si 
= r
->regs
; si
; si 
= si
->next
) 
 994                                 LogMsg("%5d: Registration(%##s) %s%s",                        c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
); 
 996         else        LogMsg("%5d: (%s) %s, but no record of client can be found!", c
,                                reason
, msg
); 
1001 mDNSlocal mDNSBool 
CheckForExistingClient(mach_port_t c
) 
1003         DNSServiceDomainEnumeration 
*e 
= DNSServiceDomainEnumerationList
; 
1004         DNSServiceBrowser           
*b 
= DNSServiceBrowserList
; 
1005         DNSServiceResolver          
*l 
= DNSServiceResolverList
; 
1006         DNSServiceRegistration      
*r 
= DNSServiceRegistrationList
; 
1007         DNSServiceBrowserQuestion   
*qptr
; 
1009         while (e 
&& e
->ClientMachPort 
!= c
) e 
= e
->next
; 
1010         while (b 
&& b
->ClientMachPort 
!= c
) b 
= b
->next
; 
1011         while (l 
&& l
->ClientMachPort 
!= c
) l 
= l
->next
; 
1012         while (r 
&& r
->ClientMachPort 
!= c
) r 
= r
->next
; 
1013         if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
); 
1016                 for (qptr 
= b
->qlist
; qptr
; qptr 
= qptr
->next
) 
1017                         LogMsg("%5d: Browser(%##s) already exists!",          c
, qptr
->q
.qname
.c
); 
1019         if (l
) LogMsg("%5d: Resolver(%##s) already exists!",          c
, l
->i
.name
.c
); 
1020         if (r
) LogMsg("%5d: Registration(%##s) already exists!",      c
, r
->regs 
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c 
: NULL
); 
1021         return(e 
|| b 
|| l 
|| r
); 
1024 mDNSlocal 
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
) 
1026         mach_msg_header_t 
*msg 
= (mach_msg_header_t 
*)voidmsg
; 
1027         (void)unusedport
; // Unused 
1028         (void)size
; // Unused 
1029         (void)info
; // Unused 
1030         if (msg
->msgh_id 
== MACH_NOTIFY_DEAD_NAME
) 
1032                 const mach_dead_name_notification_t 
*const deathMessage 
= (mach_dead_name_notification_t 
*)msg
; 
1033                 AbortClient(deathMessage
->not_port
, NULL
); 
1035                 /* Deallocate the send right that came in the dead name notification */ 
1036                 mach_port_destroy(mach_task_self(), deathMessage
->not_port
); 
1040 mDNSlocal 
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
) 
1043         kern_return_t r 
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0, 
1044                                                                                                          client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
); 
1045         // If the port already died while we were thinking about it, then abort the operation right away 
1046         if (r 
!= KERN_SUCCESS
) 
1047                 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
); 
1050 //************************************************************************************************************* 
1051 // Domain Enumeration 
1053 mDNSlocal 
void DomainEnumFound(mDNS 
*const m
, DNSQuestion 
*question
, const ResourceRecord 
*const answer
, mDNSBool AddRecord
) 
1055         kern_return_t status
; 
1057         char buffer
[MAX_ESCAPED_DOMAIN_NAME
]; 
1058         DNSServiceDomainEnumerationReplyResultType rt
; 
1059         DNSServiceDomainEnumeration 
*x 
= (DNSServiceDomainEnumeration 
*)question
->QuestionContext
; 
1061         debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
); 
1062         if (answer
->rrtype 
!= kDNSType_PTR
) return; 
1063         if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; } 
1067                 if (question 
== &x
->dom
) rt 
= DNSServiceDomainEnumerationReplyAddDomain
; 
1068                 else                     rt 
= DNSServiceDomainEnumerationReplyAddDomainDefault
; 
1072                 if (question 
== &x
->dom
) rt 
= DNSServiceDomainEnumerationReplyRemoveDomain
; 
1076         LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s", 
1077                 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
, 
1078                 !AddRecord 
? "RemoveDomain" : 
1079                 question 
== &x
->dom 
? "AddDomain" : "AddDomainDefault"); 
1081         ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
); 
1082         status 
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
); 
1083         if (status 
== MACH_SEND_TIMED_OUT
) 
1084                 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
); 
1087 mDNSexport kern_return_t 
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
, 
1090         // Check client parameter 
1091         (void)unusedserver
; // Unused 
1092         mStatus err 
= mStatus_NoError
; 
1093         const char *errormsg 
= "Unknown"; 
1094         if (client 
== (mach_port_t
)-1)      { err 
= mStatus_Invalid
; errormsg 
= "Client id -1 invalid";     goto fail
; } 
1095         if (CheckForExistingClient(client
)) { err 
= mStatus_Invalid
; errormsg 
= "Client id already in use"; goto fail
; } 
1097         mDNS_DomainType dt1 
= regDom 
? mDNS_DomainTypeRegistration        
: mDNS_DomainTypeBrowse
; 
1098         mDNS_DomainType dt2 
= regDom 
? mDNS_DomainTypeRegistrationDefault 
: mDNS_DomainTypeBrowseDefault
; 
1100         // Allocate memory, and handle failure 
1101         DNSServiceDomainEnumeration 
*x 
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
)); 
1102         if (!x
) { err 
= mStatus_NoMemoryErr
; errormsg 
= "No memory"; goto fail
; } 
1104         // Set up object, and link into list 
1105         x
->ClientMachPort 
= client
; 
1106         x
->next 
= DNSServiceDomainEnumerationList
; 
1107         DNSServiceDomainEnumerationList 
= x
; 
1109         verbosedebugf("%5d: Enumerate %s Domains", client
, regDom 
? "Registration" : "Browsing"); 
1112         err           
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
); 
1113         if (!err
) err 
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
); 
1114         if (err
) { AbortClient(client
, x
); errormsg 
= "mDNS_GetDomains"; goto fail
; } 
1116         // Succeeded: Wrap up and return 
1117         LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
); 
1118         EnableDeathNotificationForClient(client
, x
); 
1119         return(mStatus_NoError
); 
1122         LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
); 
1126 //************************************************************************************************************* 
1127 // Browse for services 
1129 mDNSlocal 
void FoundInstance(mDNS 
*const m
, DNSQuestion 
*question
, const ResourceRecord 
*const answer
, mDNSBool AddRecord
) 
1133         if (answer
->rrtype 
!= kDNSType_PTR
) 
1134                 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; } 
1137         domainname type
, domain
; 
1138         if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
)) 
1140                 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", 
1141                         answer
->name
->c
, answer
->rdata
->u
.name
.c
); 
1145         DNSServiceBrowserResult 
*x 
= mallocL("DNSServiceBrowserResult", sizeof(*x
)); 
1146         if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; } 
1148         verbosedebugf("FoundInstance: %s %##s", AddRecord 
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
); 
1149         AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
); 
1151                  x
->resultType 
= DNSServiceBrowserReplyAddInstance
; 
1152         else x
->resultType 
= DNSServiceBrowserReplyRemoveInstance
; 
1155         DNSServiceBrowser 
*browser 
= (DNSServiceBrowser 
*)question
->QuestionContext
; 
1156         DNSServiceBrowserResult 
**p 
= &browser
->results
; 
1157         while (*p
) p 
= &(*p
)->next
; 
1161 mDNSlocal mStatus 
AddDomainToBrowser(DNSServiceBrowser 
*browser
, const domainname 
*d
) 
1163         mStatus err 
= mStatus_NoError
; 
1164         DNSServiceBrowserQuestion 
*ptr
, *question 
= NULL
; 
1166         for (ptr 
= browser
->qlist
; ptr
; ptr 
= ptr
->next
) 
1168                 if (SameDomainName(&ptr
->q
.qname
, d
)) 
1169                         { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; } 
1172         question 
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
)); 
1173         if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; } 
1174         AssignDomainName(&question
->domain
, d
); 
1175         question
->next 
= browser
->qlist
; 
1176         browser
->qlist 
= question
; 
1177         LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
); 
1178         err 
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
); 
1179         if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
); 
1183 mDNSexport 
void DefaultBrowseDomainChanged(const domainname 
*d
, mDNSBool add
) 
1185         DNSServiceBrowser 
*ptr
; 
1187         debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add 
? "Adding" : "Removing", d
->c
); 
1188         for (ptr 
= DNSServiceBrowserList
; ptr
; ptr 
= ptr
->next
) 
1190                 if (ptr
->DefaultDomain
) 
1194                                 mStatus err 
= AddDomainToBrowser(ptr
, d
); 
1195                                 if (err 
&& err 
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
); 
1199                                 DNSServiceBrowserQuestion 
**q 
= &ptr
->qlist
; 
1202                                         if (SameDomainName(&(*q
)->domain
, d
)) 
1204                                                 DNSServiceBrowserQuestion 
*remove 
= *q
; 
1206                                                 if (remove
->q
.LongLived
) 
1208                                                         // give goodbyes for known answers.  note that since events are sent to client via udns_execute(), 
1209                                                         // we don't need to worry about the question being cancelled mid-loop 
1210                                                         CacheRecord 
*ka 
= remove
->q
.uDNS_info
.knownAnswers
; 
1211                                                         while (ka
) { remove
->q
.QuestionCallback(&mDNSStorage
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka 
= ka
->next
; } 
1213                                                 mDNS_StopBrowse(&mDNSStorage
, &remove
->q
); 
1214                                                 freeL("DNSServiceBrowserQuestion", remove 
); 
1219                             LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
); 
1225 mDNSexport kern_return_t 
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
, 
1226         DNSCString regtype
, DNSCString domain
) 
1228         // Check client parameter 
1229         (void)unusedserver
;             // Unused 
1230         mStatus err 
= mStatus_NoError
; 
1231         const char *errormsg 
= "Unknown"; 
1232         DNameListElem 
*SearchDomains 
= NULL
, *sdPtr
; 
1234         if (client 
== (mach_port_t
)-1)      { err 
= mStatus_Invalid
; errormsg 
= "Client id -1 invalid";     goto fail
; } 
1235         if (CheckForExistingClient(client
)) { err 
= mStatus_Invalid
; errormsg 
= "Client id already in use"; goto fail
; } 
1237         // Check other parameters 
1240         mDNSs32 NumSubTypes 
= ChopSubTypes(regtype
);    // Note: Modifies regtype string to remove trailing subtypes 
1241         if (NumSubTypes 
< 0 || NumSubTypes 
> 1)               { errormsg 
= "Bad Service SubType"; goto badparam
; } 
1242         if (NumSubTypes 
== 1 && !AppendDNSNameString(&t
, regtype 
+ strlen(regtype
) + 1)) 
1243                                                               { errormsg 
= "Bad Service SubType"; goto badparam
; } 
1244         if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg 
= "Illegal regtype";     goto badparam
; } 
1246         if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg 
= "Illegal regtype";     goto badparam
; } 
1247         if (temp
.c
[0] > 15 && (!domain 
|| domain
[0] == 0)) domain 
= "local."; // For over-long service types, we only allow domain "local" 
1249         // Allocate memory, and handle failure 
1250         DNSServiceBrowser 
*x 
= mallocL("DNSServiceBrowser", sizeof(*x
)); 
1251         if (!x
) { err 
= mStatus_NoMemoryErr
; errormsg 
= "No memory"; goto fail
; } 
1253         // Set up object, and link into list 
1254         AssignDomainName(&x
->type
, &t
); 
1255         x
->ClientMachPort 
= client
; 
1259         x
->next 
= DNSServiceBrowserList
; 
1260         DNSServiceBrowserList 
= x
; 
1264                 // Start browser for an explicit domain 
1265                 x
->DefaultDomain 
= mDNSfalse
; 
1266                 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg 
= "Illegal domain";  goto badparam
; }               
1267                 err 
= AddDomainToBrowser(x
, &d
); 
1268                 if (err
) { AbortClient(client
, x
); errormsg 
= "AddDomainToBrowser"; goto fail
; } 
1272                 // Start browser on all domains 
1273                 x
->DefaultDomain 
= mDNStrue
; 
1274                 SearchDomains 
= mDNSPlatformGetSearchDomainList(); 
1275                 if (!SearchDomains
) { AbortClient(client
, x
); errormsg 
= "GetSearchDomainList"; goto fail
; } 
1276                 for (sdPtr 
= SearchDomains
; sdPtr
; sdPtr 
= sdPtr
->next
) 
1278                         err 
= AddDomainToBrowser(x
, &sdPtr
->name
); 
1281                                 // only terminally bail if .local fails 
1282                                 if (!SameDomainName(&localdomain
, &sdPtr
->name
)) 
1283                                         LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
); 
1284                                 else { AbortClient(client
, x
); errormsg 
= "AddDomainToBrowser"; goto fail
; } 
1289         // Succeeded: Wrap up and return 
1290         EnableDeathNotificationForClient(client
, x
); 
1291         mDNS_FreeDNameList(SearchDomains
); 
1292         return(mStatus_NoError
); 
1295         err 
= mStatus_BadParamErr
; 
1297         LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
); 
1298         if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
); 
1302 //************************************************************************************************************* 
1303 // Resolve Service Info 
1305 mDNSlocal 
void FoundInstanceInfo(mDNS 
*const m
, ServiceInfoQuery 
*query
) 
1307         kern_return_t status
; 
1308         DNSServiceResolver 
*x 
= (DNSServiceResolver 
*)query
->ServiceInfoQueryContext
; 
1309         NetworkInterfaceInfoOSX 
*ifx 
= (NetworkInterfaceInfoOSX 
*)query
->info
->InterfaceID
; 
1310         if (query
->info
->InterfaceID 
== mDNSInterface_LocalOnly
) ifx 
= mDNSNULL
; 
1311         struct sockaddr_storage interface
; 
1312         struct sockaddr_storage address
; 
1314         int i
, pstrlen 
= query
->info
->TXTinfo
[0]; 
1317         //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name); 
1319         if (query
->info
->TXTlen 
> sizeof(cstring
)) return; 
1321         bzero(&interface
, sizeof(interface
)); 
1322         bzero(&address
,   sizeof(address
)); 
1324         if (ifx 
&& ifx
->ifinfo
.ip
.type 
== mDNSAddrType_IPv4
) 
1326                 struct sockaddr_in 
*sin 
= (struct sockaddr_in
*)&interface
; 
1327                 sin
->sin_len         
= sizeof(*sin
); 
1328                 sin
->sin_family      
= AF_INET
; 
1330                 sin
->sin_addr
.s_addr 
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
; 
1332         else if (ifx 
&& ifx
->ifinfo
.ip
.type 
== mDNSAddrType_IPv6
) 
1334                 struct sockaddr_in6 
*sin6 
= (struct sockaddr_in6
*)&interface
; 
1335                 sin6
->sin6_len       
= sizeof(*sin6
); 
1336                 sin6
->sin6_family    
= AF_INET6
; 
1337                 sin6
->sin6_flowinfo  
= 0; 
1338                 sin6
->sin6_port      
= 0; 
1339                 sin6
->sin6_addr          
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
; 
1340                 sin6
->sin6_scope_id  
= ifx
->scope_id
; 
1343         if (query
->info
->ip
.type 
== mDNSAddrType_IPv4
) 
1345                 struct sockaddr_in 
*sin 
= (struct sockaddr_in
*)&address
; 
1346                 sin
->sin_len           
= sizeof(*sin
); 
1347                 sin
->sin_family        
= AF_INET
; 
1348                 sin
->sin_port          
= query
->info
->port
.NotAnInteger
; 
1349                 sin
->sin_addr
.s_addr   
= query
->info
->ip
.ip
.v4
.NotAnInteger
; 
1353                 struct sockaddr_in6 
*sin6 
= (struct sockaddr_in6
*)&address
; 
1354                 sin6
->sin6_len           
= sizeof(*sin6
); 
1355                 sin6
->sin6_family        
= AF_INET6
; 
1356                 sin6
->sin6_port          
= query
->info
->port
.NotAnInteger
; 
1357                 sin6
->sin6_flowinfo      
= 0; 
1358                 sin6
->sin6_addr                  
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
; 
1359                 sin6
->sin6_scope_id      
= ifx 
? ifx
->scope_id 
: 0; 
1362         // The OS X DNSServiceResolverResolve() API is defined using a C-string, 
1363         // but the mDNS_StartResolveService() call actually returns a packed block of P-strings. 
1364         // Hence we have to convert the P-string(s) to a C-string before returning the result to the client. 
1365         // ASCII-1 characters are used in the C-string as boundary markers, 
1366         // to indicate the boundaries between the original constituent P-strings. 
1367         for (i
=1; i
<query
->info
->TXTlen
; i
++) 
1370                         cstring
[i
-1] = query
->info
->TXTinfo
[i
]; 
1374                         pstrlen 
= query
->info
->TXTinfo
[i
]; 
1377         cstring
[i
-1] = 0;               // Put the terminating NULL on the end 
1379         LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
, 
1380                 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
)); 
1381         status 
= DNSServiceResolverReply_rpc(x
->ClientMachPort
, 
1382                 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
); 
1383         if (status 
== MACH_SEND_TIMED_OUT
) 
1384                 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
); 
1387 mDNSexport kern_return_t 
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
, 
1388         DNSCString name
, DNSCString regtype
, DNSCString domain
) 
1390         // Check client parameter 
1391         (void)unusedserver
;             // Unused 
1392         mStatus err 
= mStatus_NoError
; 
1393         const char *errormsg 
= "Unknown"; 
1394         if (client 
== (mach_port_t
)-1)      { err 
= mStatus_Invalid
; errormsg 
= "Client id -1 invalid";     goto fail
; } 
1395         if (CheckForExistingClient(client
)) { err 
= mStatus_Invalid
; errormsg 
= "Client id already in use"; goto fail
; } 
1397         // Check other parameters 
1399         domainname t
, d
, srv
; 
1400         if (!name
[0]    || !MakeDomainLabelFromLiteralString(&n
, name
))        { errormsg 
= "Bad Instance Name"; goto badparam
; } 
1401         if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
))      { errormsg 
= "Bad Service Type";  goto badparam
; } 
1402         if (!domain
[0]  || !MakeDomainNameFromDNSNameString(&d
, domain
))       { errormsg 
= "Bad Domain";        goto badparam
; } 
1403         if (!ConstructServiceName(&srv
, &n
, &t
, &d
))                           { errormsg 
= "Bad Name";          goto badparam
; } 
1405         // Allocate memory, and handle failure 
1406         DNSServiceResolver 
*x 
= mallocL("DNSServiceResolver", sizeof(*x
)); 
1407         if (!x
) { err 
= mStatus_NoMemoryErr
; errormsg 
= "No memory"; goto fail
; } 
1409         // Set up object, and link into list 
1410         x
->ClientMachPort 
= client
; 
1411         x
->i
.InterfaceID 
= mDNSInterface_Any
; 
1413         x
->ReportTime 
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
); 
1414         x
->next 
= DNSServiceResolverList
; 
1415         DNSServiceResolverList 
= x
; 
1418         LogOperation("%5d: DNSServiceResolve(%##s) START", client
, x
->i
.name
.c
); 
1419         err 
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
); 
1420         if (err
) { AbortClient(client
, x
); errormsg 
= "mDNS_StartResolveService"; goto fail
; } 
1422         // Succeeded: Wrap up and return 
1423         EnableDeathNotificationForClient(client
, x
); 
1424         return(mStatus_NoError
); 
1427         err 
= mStatus_BadParamErr
; 
1429         LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
); 
1433 //************************************************************************************************************* 
1436 mDNSexport 
void RecordUpdatedNiceLabel(mDNS 
*const m
, mDNSs32 delay
) 
1438         m
->p
->NotifyUser 
= NonZeroTime(m
->timenow 
+ delay
); 
1441 mDNSlocal 
void RegCallback(mDNS 
*const m
, ServiceRecordSet 
*const srs
, mStatus result
) 
1443         ServiceInstance 
*si 
= (ServiceInstance
*)srs
->ServiceContext
; 
1445         if (result 
== mStatus_NoError
) 
1447                 kern_return_t status
; 
1448                 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
)); 
1449                 status 
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
); 
1450                 if (status 
== MACH_SEND_TIMED_OUT
) 
1451                         AbortBlockedClient(si
->ClientMachPort
, "registration success", si
); 
1452                 if (si
->autoname 
&& CountPeerRegistrations(m
, srs
) == 0) 
1453                         RecordUpdatedNiceLabel(m
, 0);   // Successfully got new name, tell user immediately 
1456         else if (result 
== mStatus_NameConflict
) 
1458                 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
)); 
1459                 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered 
1460                 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well. 
1461                 if (si
->autoname 
&& CountPeerRegistrations(m
, srs
) == 0) 
1463                         // On conflict for an autoname service, rename and reregister *all* autoname services 
1464                         IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
); 
1465                         m
->MainCallback(m
, mStatus_ConfigChanged
); 
1467                 else if (si
->autoname
) 
1469             mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
); 
1474                         // If we get a name conflict, we tell the client about it, and then they are expected to dispose 
1475                         // of their registration in the usual way (which we will catch via client death notification). 
1476                         // If the Mach queue is full, we forcibly abort the client immediately. 
1477                         kern_return_t status 
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
); 
1478                         if (status 
== MACH_SEND_TIMED_OUT
) 
1479                                 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
); 
1483         else if (result 
== mStatus_MemFree
) 
1487                         debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
); 
1488                         si
->autorename 
= mDNSfalse
; 
1489                         si
->name 
= m
->nicelabel
; 
1490                         mDNS_RenameAndReregisterService(m
, srs
, &si
->name
); 
1494                         // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list 
1495                         DNSServiceRegistration 
*r
; 
1496                         for (r 
= DNSServiceRegistrationList
; r
; r 
= r
->next
) 
1498                                 ServiceInstance 
*sp 
= r
->regs
, *prev 
= NULL
; 
1503                                                 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
->c
);                          
1504                                                 if (prev
) prev
->next 
= sp
->next
; 
1505                                                 else r
->regs 
= sp
->next
; 
1513                         FreeServiceInstance(si
); 
1517         else if (result 
!= mStatus_NATTraversal
) 
1518                 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
); 
1521 mDNSlocal mStatus 
AddServiceInstance(DNSServiceRegistration 
*x
, const domainname 
*domain
) 
1524         ServiceInstance 
*si 
= NULL
; 
1525         AuthRecord 
*SubTypes 
= NULL
; 
1527         for (si 
= x
->regs
; si
; si 
= si
->next
) 
1529                 if (SameDomainName(&si
->domain
, domain
)) 
1530                         { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; } 
1533         SubTypes 
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
); 
1534         if (x
->NumSubTypes 
&& !SubTypes
) return mStatus_NoMemoryErr
; 
1536         si 
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
); 
1537         if (!si
) return mStatus_NoMemoryErr
; 
1539         si
->ClientMachPort 
= x
->ClientMachPort
; 
1540         si
->autorename 
= mDNSfalse
; 
1541         si
->autoname 
= x
->autoname
; 
1542         si
->name 
= x
->autoname 
? mDNSStorage
.nicelabel 
: x
->name
; 
1543         si
->domain 
= *domain
; 
1545         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
); 
1553                 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
); 
1554                 freeL("ServiceInstance", si
); 
1559 mDNSexport 
void DefaultRegDomainChanged(const domainname 
*d
, mDNSBool add
) 
1561         DNSServiceRegistration 
*reg
; 
1563         for (reg 
= DNSServiceRegistrationList
; reg
; reg 
= reg
->next
) 
1565                 if (reg
->DefaultDomain
) 
1569                                 AddServiceInstance(reg
, d
); 
1573                                 ServiceInstance 
*si 
= reg
->regs
, *prev 
= NULL
; 
1576                                         if (SameDomainName(&si
->domain
, d
)) 
1578                                                 if (prev
) prev
->next 
= si
->next
; 
1579                                                 else reg
->regs 
= si
->next
; 
1580                                                 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
)) 
1581                                                         FreeServiceInstance(si
);  // only free memory synchronously on error 
1587                                 if (!si
) debugf("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
); // normal if registration failed 
1593 mDNSexport kern_return_t 
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
, 
1594         DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
) 
1596         (void)unusedserver
;             // Unused 
1597         mStatus err 
= mStatus_NoError
; 
1598         const char *errormsg 
= "Unknown"; 
1600         // older versions of this code passed the port via mach IPC as an int. 
1601         // we continue to pass it as 4 bytes to maintain binary compatibility, 
1602         // but now ensure that the network byte order is preserved by using a struct 
1604         port
.b
[0] = IpPort
.bytes
[2]; 
1605         port
.b
[1] = IpPort
.bytes
[3]; 
1607         if (client 
== (mach_port_t
)-1)      { err 
= mStatus_Invalid
; errormsg 
= "Client id -1 invalid";     goto fail
; } 
1608         if (CheckForExistingClient(client
)) { err 
= mStatus_Invalid
; errormsg 
= "Client id already in use"; goto fail
; } 
1610     // Check for sub-types after the service type 
1611         size_t reglen 
= strlen(regtype
) + 1; 
1612         if (reglen 
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg 
= "reglen too long"; goto badparam
; } 
1613         mDNSs32 NumSubTypes 
= ChopSubTypes(regtype
);    // Note: Modifies regtype string to remove trailing subtypes 
1614         if (NumSubTypes 
< 0) { errormsg 
= "Bad Service SubType"; goto badparam
; } 
1616         // Check other parameters 
1620         if (!name
[0]) n 
= mDNSStorage
.nicelabel
; 
1621         else if (!MakeDomainLabelFromLiteralString(&n
, name
))                  { errormsg 
= "Bad Instance Name"; goto badparam
; } 
1622         if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
))      { errormsg 
= "Bad Service Type";  goto badparam
; } 
1623         if (!MakeDomainNameFromDNSNameString(&d
, *domain 
? domain 
: "local.")) { errormsg 
= "Bad Domain";        goto badparam
; } 
1624         if (!ConstructServiceName(&srv
, &n
, &t
, &d
))                           { errormsg 
= "Bad Name";          goto badparam
; } 
1626         unsigned char txtinfo
[1024] = ""; 
1627         unsigned int data_len 
= 0; 
1628         unsigned int size 
= sizeof(RDataBody
); 
1629         unsigned char *pstring 
= &txtinfo
[data_len
]; 
1630         char *ptr 
= txtRecord
; 
1632         // The OS X DNSServiceRegistrationCreate() API is defined using a C-string, 
1633         // but the mDNS_RegisterService() call actually requires a packed block of P-strings. 
1634         // Hence we have to convert the C-string to a P-string. 
1635         // ASCII-1 characters are allowed in the C-string as boundary markers, 
1636         // so that a single C-string can be used to represent one or more P-strings. 
1639                 if (++data_len 
>= sizeof(txtinfo
)) { errormsg 
= "TXT record too long"; goto badtxt
; } 
1640                 if (*ptr 
== 1)          // If this is our boundary marker, start a new P-string 
1642                         pstring 
= &txtinfo
[data_len
]; 
1648                         if (pstring
[0] == 255) { errormsg 
= "TXT record invalid (component longer than 255)"; goto badtxt
; } 
1649                         pstring
[++pstring
[0]] = *ptr
++; 
1654         if (size 
< data_len
) 
1657         // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with 
1658         // a port number of zero. When two instances of the protected client are allowed to run on one 
1659         // machine, we don't want to see misleading "Bogus client" messages in syslog and the console. 
1660         if (port
.NotAnInteger
) 
1662                 int count 
= CountExistingRegistrations(&srv
, port
); 
1664                         LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.", 
1665                                    client
, count
+1, srv
.c
, mDNSVal16(port
)); 
1668         // Allocate memory, and handle failure 
1669         DNSServiceRegistration 
*x 
= mallocL("DNSServiceRegistration", sizeof(*x
)); 
1670         if (!x
) { err 
= mStatus_NoMemoryErr
; errormsg 
= "No memory"; goto fail
; } 
1671         bzero(x
, sizeof(*x
)); 
1673         // Set up object, and link into list 
1674         x
->ClientMachPort 
= client
; 
1675         x
->DefaultDomain 
= !domain
[0]; 
1676         x
->autoname 
= (!name
[0]); 
1678         x
->NumSubTypes 
= NumSubTypes
; 
1679         memcpy(x
->regtype
, regtype
, reglen
); 
1683         memcpy(x
->txtinfo
, txtinfo
, 1024); 
1684         x
->txt_len 
= data_len
;   
1688         x
->next 
= DNSServiceRegistrationList
; 
1689         DNSServiceRegistrationList 
= x
; 
1691         LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START", 
1692                 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
)); 
1694         err 
= AddServiceInstance(x
, &d
); 
1695         if (err
) { AbortClient(client
, x
); errormsg 
= "mDNS_RegisterService"; goto fail
; }  // bail if .local (or explicit domain) fails 
1697         if (x
->DefaultDomain
) 
1699                 DNameListElem 
*ptr
, *regdomains 
= mDNSPlatformGetRegDomainList(); 
1700                 for (ptr 
= regdomains
; ptr
; ptr 
= ptr
->next
) 
1701                         AddServiceInstance(x
, &ptr
->name
); 
1702                 mDNS_FreeDNameList(regdomains
); 
1705         // Succeeded: Wrap up and return 
1706         EnableDeathNotificationForClient(client
, x
); 
1707         return(mStatus_NoError
); 
1710         LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
); 
1712         err 
= mStatus_BadParamErr
; 
1714         LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)", 
1715                    client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
); 
1719 mDNSlocal CFUserNotificationRef gNotification    
= NULL
; 
1720 mDNSlocal CFRunLoopSourceRef    gNotificationRLS 
= NULL
; 
1721 mDNSlocal domainlabel           gNotificationPrefHostLabel
;     // The prefs as they were the last time we saw them 
1722 mDNSlocal domainlabel           gNotificationPrefNiceLabel
; 
1723 mDNSlocal domainlabel           gNotificationUserHostLabel
;     // The prefs as they were the last time the user changed them 
1724 mDNSlocal domainlabel           gNotificationUserNiceLabel
; 
1726 mDNSlocal 
void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
) 
1728         (void)responseFlags
;    // Unused 
1729         if (userNotification 
!= gNotification
) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef"); 
1730         if (gNotificationRLS
) 
1732                 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
); 
1733                 CFRelease(gNotificationRLS
); 
1734                 gNotificationRLS 
= NULL
; 
1735                 CFRelease(gNotification
); 
1736                 gNotification 
= NULL
; 
1738         // By dismissing the alert, the user has conceptually acknowleged the rename. 
1739         // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".) 
1740         // If we get *another* conflict, the new alert should refer to the 'old'. 
1741         // name as now being "computer-2.local", not "computer.local" 
1742         gNotificationUserHostLabel 
= gNotificationPrefHostLabel
; 
1743         gNotificationUserNiceLabel 
= gNotificationPrefNiceLabel
; 
1746 mDNSlocal 
void ShowNameConflictNotification(CFStringRef header
, CFStringRef subtext
) 
1748         CFMutableDictionaryRef dictionary 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1749         if (!dictionary
) return; 
1750         CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
); 
1751         CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
); 
1753         CFURLRef urlRef 
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true); 
1754         if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); } 
1756         if (gNotification
)      // If notification already on-screen, update it in place 
1757                 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
); 
1758         else                            // else, we need to create it 
1761                 gNotification 
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
); 
1762                 if (!gNotification
) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; } 
1763                 gNotificationRLS 
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0); 
1764                 if (!gNotificationRLS
) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification 
= NULL
; return; } 
1765                 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS
, kCFRunLoopDefaultMode
); 
1768         CFRelease(dictionary
); 
1771 // This updates either the text of the field currently labelled "Local Hostname", 
1772 // or the text of the field currently labelled "Computer Name" 
1773 // in the Sharing Prefs Control Panel 
1774 mDNSlocal 
void RecordUpdatedName(const mDNS 
*const m
, const domainlabel 
*const olddl
, const domainlabel 
*const newdl
, 
1775         const char *const msg
, const char *const suffix
, const CFStringRef subtext
) 
1777         char oldname
[MAX_DOMAIN_LABEL
+1]; 
1778         char newname
[MAX_DOMAIN_LABEL
+1]; 
1779         ConvertDomainLabelToCString_unescaped(olddl
, oldname
); 
1780         ConvertDomainLabelToCString_unescaped(newdl
, newname
); 
1781         const CFStringRef      cfoldname 
= CFStringCreateWithCString(NULL
, oldname
,  kCFStringEncodingUTF8
); 
1782         const CFStringRef      cfnewname 
= CFStringCreateWithCString(NULL
, newname
,  kCFStringEncodingUTF8
); 
1783         const CFStringRef      f1        
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
); 
1784         const CFStringRef      f2        
= CFStringCreateWithCString(NULL
, " “%@%s” ", kCFStringEncodingUTF8
); 
1785         const SCPreferencesRef session   
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
); 
1786         if (!cfoldname 
|| !cfnewname 
|| !f1 
|| !f2 
|| !session 
|| !SCPreferencesLock(session
, 0))       // If we can't get the lock don't wait 
1787                 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session"); 
1790                 const CFStringRef       s0           
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
); 
1791                 const CFStringRef       s1           
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
); 
1792                 const CFStringRef       s2           
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
); 
1793                 // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each 
1794                 // element of the array individually for us, and then concatenate the results to make the final message. 
1795                 // This lets us have the relevant bits localized, but not the literal names, which should not be translated. 
1796                 // On Panther this does not work, so we just build the string directly, and it will not be translated. 
1797                 const CFMutableStringRef alertHeader 
= 
1798                         (OSXVers 
< 8) ? CFStringCreateMutable(NULL
, 0) : (CFMutableStringRef
)CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
1800                 if (newdl 
== &gNotificationPrefHostLabel
) result 
= SCPreferencesSetLocalHostName(session
, cfnewname
); 
1801                 else result 
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
); 
1802                 if (!result 
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0 
|| !s1 
|| !s2 
|| !alertHeader
) 
1803                         LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences"); 
1804                 else if (m
->p
->NotifyUser
) 
1808                         CFStringRef userName 
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
); 
1811                                 CFRelease(userName
); 
1812                                 typedef void CFStringAppendFN(CFMutableStringRef theString
, CFStringRef appendedString
); 
1813                                 CFStringAppendFN 
*const append 
= (OSXVers 
< 8) ? &CFStringAppend 
: (CFStringAppendFN
*)&CFArrayAppendValue
; 
1814                                 append(alertHeader
, s0
); 
1815                                 append(alertHeader
, s1
); 
1816                                 append(alertHeader
, CFSTR("is already in use on this network.")); 
1817                                 append(alertHeader
, CFSTR("  ")); 
1818                                 append(alertHeader
, CFSTR("The name has been changed to")); 
1819                                 append(alertHeader
, s2
); 
1820                                 append(alertHeader
, CFSTR("automatically.")); 
1821                                 ShowNameConflictNotification(alertHeader
, subtext
); 
1824                 if (s0
)          CFRelease(s0
); 
1825                 if (s1
)          CFRelease(s1
); 
1826                 if (s2
)          CFRelease(s2
); 
1827                 if (alertHeader
) CFRelease(alertHeader
); 
1828                 SCPreferencesUnlock(session
); 
1830         if (cfoldname
) CFRelease(cfoldname
); 
1831         if (cfnewname
) CFRelease(cfnewname
); 
1832         if (f1
)        CFRelease(f1
); 
1833         if (f2
)        CFRelease(f2
); 
1834         if (session
)   CFRelease(session
); 
1837 mDNSlocal 
void mDNS_StatusCallback(mDNS 
*const m
, mStatus result
) 
1840         if (result 
== mStatus_NoError
)   
1842                 // One second pause in case we get a Computer Name update too -- don't want to alert the user twice 
1843                 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
); 
1845         else if (result 
== mStatus_ConfigChanged
) 
1847                 // If the user-specified hostlabel from System Configuration has changed since the last time 
1848                 // we saw it, and *we* didn't change it, then that implies that the user has changed it, 
1849                 // so we auto-dismiss the name conflict alert. 
1850                 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, gNotificationPrefHostLabel
.c
) || 
1851                         !SameDomainLabel(m
->p
->usernicelabel
.c
, gNotificationPrefNiceLabel
.c
)) 
1853                         gNotificationUserHostLabel 
= gNotificationPrefHostLabel 
= m
->p
->userhostlabel
; 
1854                         gNotificationUserNiceLabel 
= gNotificationPrefNiceLabel 
= m
->p
->usernicelabel
; 
1855                         // If we're showing a name conflict notification, and the user has manually edited 
1856                         // the name to remedy the conflict, we should now remove the notification window. 
1857                         if (gNotificationRLS
) CFUserNotificationCancel(gNotification
); 
1860                 DNSServiceRegistration 
*r
; 
1861                 for (r 
= DNSServiceRegistrationList
; r
; r
=r
->next
) 
1864                                 ServiceInstance 
*si
; 
1865                                 for (si 
= r
->regs
; si
; si 
= si
->next
) 
1867                                         if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
)) 
1869                                                 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
); 
1870                                                 si
->autorename 
= mDNStrue
; 
1871                                                 if (mDNS_DeregisterService(m
, &si
->srs
))        // If service deregistered already, we can re-register immediately 
1872                                                         RegCallback(m
, &si
->srs
, mStatus_MemFree
); 
1876                 udsserver_handle_configchange(); 
1878         else if (result 
== mStatus_GrowCache
) 
1880                 // Allocate another chunk of cache storage 
1881                 CacheEntity 
*storage 
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
); 
1882                 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
); 
1886 //************************************************************************************************************* 
1887 // Add / Update / Remove records from existing Registration 
1889 mDNSexport kern_return_t 
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
, 
1890         int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t 
*reference
) 
1892         // Check client parameter 
1894         mStatus err 
= mStatus_NoError
; 
1895         const char *errormsg 
= "Unknown"; 
1896         if (client 
== (mach_port_t
)-1) { err 
= mStatus_Invalid
;         errormsg 
= "Client id -1 invalid"; goto fail
; } 
1897         DNSServiceRegistration 
*x 
= DNSServiceRegistrationList
; 
1898         ServiceInstance 
*si
; 
1900         (void)unusedserver
;             // Unused 
1901         while (x 
&& x
->ClientMachPort 
!= client
) x 
= x
->next
; 
1902         if (!x
)                        { err 
= mStatus_BadReferenceErr
; errormsg 
= "No such client";       goto fail
; } 
1904         // Check other parameters 
1905         if (data_len 
> 8192) { err 
= mStatus_BadParamErr
; errormsg 
= "data_len > 8K"; goto fail
; } 
1906         if (data_len 
> sizeof(RDataBody
)) size 
= data_len
; 
1907         else size 
= sizeof(RDataBody
); 
1910         *reference 
= (natural_t
)id
; 
1911         for (si 
= x
->regs
; si
; si 
= si
->next
) 
1913                 // Allocate memory, and handle failure 
1914                 ExtraResourceRecord 
*extra 
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
); 
1915                 if (!extra
) { err 
= mStatus_NoMemoryErr
; errormsg 
= "No memory"; goto fail
; } 
1917                 // Fill in type, length, and data of new record 
1918                 extra
->r
.resrec
.rrtype 
= type
; 
1919                 extra
->r
.rdatastorage
.MaxRDLength 
= size
; 
1920                 extra
->r
.resrec
.rdlength          
= data_len
; 
1921                 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
); 
1924                 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p", 
1925                                          client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
); 
1926                 err 
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
); 
1930                         freeL("Extra Resource Record", extra
); 
1931                         errormsg 
= "mDNS_AddRecordToService"; 
1935                 extra
->ClientID 
= id
; 
1938         return mStatus_NoError
; 
1941         LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
); 
1942         return mStatus_UnknownErr
; 
1945 mDNSlocal 
void UpdateCallback(mDNS 
*const m
, AuthRecord 
*const rr
, RData 
*OldRData
) 
1948         if (OldRData 
!= &rr
->rdatastorage
) 
1949                 freeL("Old RData", OldRData
); 
1952 mDNSlocal mStatus 
UpdateRecord(ServiceRecordSet 
*srs
, mach_port_t client
, AuthRecord 
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
) 
1954     // Check client parameter 
1955         mStatus err 
= mStatus_NoError
; 
1956         const char *errormsg 
= "Unknown"; 
1957         domainname 
*name 
= (domainname 
*)""; 
1959         name 
= srs
->RR_SRV
.resrec
.name
; 
1961         unsigned int size 
= sizeof(RDataBody
); 
1962     if (size 
< data_len
) 
1965         // Allocate memory, and handle failure 
1966         RData 
*newrdata 
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
); 
1967         if (!newrdata
) { err 
= mStatus_NoMemoryErr
; errormsg 
= "No memory"; goto fail
; } 
1969         // Fill in new length, and data 
1970         newrdata
->MaxRDLength 
= size
; 
1971         memcpy(&newrdata
->u
, data
, data_len
); 
1973         // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, 
1974         // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s". 
1975         // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. 
1976         if (rr
->resrec
.rrtype 
== kDNSType_TXT 
&& data_len 
== 0) { data_len 
= 1; newrdata
->u
.txt
.c
[0] = 0; } 
1979         LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)", 
1980                 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
); 
1982         err 
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
); 
1985                 errormsg 
= "mDNS_Update"; 
1986                 freeL("RData", newrdata
); 
1989         return(mStatus_NoError
); 
1992         LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
); 
1996 mDNSexport kern_return_t 
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
, 
1997                 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
) 
1999     // Check client parameter 
2000         mStatus err 
= mStatus_NoError
; 
2001         const char *errormsg 
= "Unknown"; 
2002         domainname 
*name 
= (domainname 
*)""; 
2003         ServiceInstance 
*si
; 
2005         (void)unusedserver
; // unused 
2006     if (client 
== (mach_port_t
)-1) { err 
= mStatus_Invalid
;         errormsg 
= "Client id -1 invalid"; goto fail
; } 
2007         DNSServiceRegistration 
*x 
= DNSServiceRegistrationList
; 
2008         while (x 
&& x
->ClientMachPort 
!= client
) x 
= x
->next
; 
2009         if (!x
)                        { err 
= mStatus_BadReferenceErr
; errormsg 
= "No such client";       goto fail
; } 
2011         // Check other parameters 
2012         if (data_len 
> 8192) { err 
= mStatus_BadParamErr
; errormsg 
= "data_len > 8K"; goto fail
; } 
2014         for (si 
= x
->regs
; si
; si 
= si
->next
) 
2016                 AuthRecord 
*r 
= NULL
; 
2018                 // Find the record we're updating. NULL reference means update the primary TXT record 
2019                 if (!reference
) r 
= &si
->srs
.RR_TXT
; 
2022                         ExtraResourceRecord 
*ptr
; 
2023                         for (ptr 
= si
->srs
.Extras
; ptr
; ptr 
= ptr
->next
) 
2025                                 if ((natural_t
)ptr
->ClientID 
== reference
) 
2026                                         { r 
= &ptr
->r
; break; } 
2028                         if (!r
) { err 
= mStatus_BadReferenceErr
; errormsg 
= "No such record"; goto fail
; } 
2030                 err 
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
); 
2031                 if (err
) goto fail
;  //!!!KRS this will cause failures for non-local defaults! 
2034         return mStatus_NoError
; 
2037         LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
); 
2041 mDNSlocal mStatus 
RemoveRecord(ServiceRecordSet 
*srs
, ExtraResourceRecord 
*extra
, mach_port_t client
) 
2043         domainname 
*name 
= srs
->RR_SRV
.resrec
.name
; 
2044         mStatus err 
= mStatus_NoError
; 
2047         LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
); 
2049         err 
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
); 
2050         if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
); 
2055 mDNSexport kern_return_t 
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
, 
2056         natural_t reference
) 
2058         // Check client parameter 
2059         (void)unusedserver
;             // Unused 
2060         mStatus err 
= mStatus_NoError
; 
2061         const char *errormsg 
= "Unknown"; 
2062         if (client 
== (mach_port_t
)-1) { err 
= mStatus_Invalid
;         errormsg 
= "Client id -1 invalid"; goto fail
; } 
2063         DNSServiceRegistration 
*x 
= DNSServiceRegistrationList
; 
2064         ServiceInstance 
*si
; 
2066         while (x 
&& x
->ClientMachPort 
!= client
) x 
= x
->next
; 
2067         if (!x
)                        { err 
= mStatus_BadReferenceErr
; errormsg 
= "No such client";       goto fail
; } 
2069         for (si 
= x
->regs
; si
; si 
= si
->next
) 
2071                 ExtraResourceRecord 
*e
; 
2072                 for (e 
= si
->srs
.Extras
; e
; e 
= e
->next
) 
2074                         if ((natural_t
)e
->ClientID 
== reference
) 
2076                                 err 
= RemoveRecord(&si
->srs
, e
, client
); 
2080                 if (!e
) { err 
= mStatus_BadReferenceErr
; errormsg 
= "No such reference"; goto fail
; } 
2083         return mStatus_NoError
; 
2086         LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
); 
2090 //************************************************************************************************************* 
2093 mDNSlocal 
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
) 
2095         mig_reply_error_t 
*request 
= msg
; 
2096         mig_reply_error_t 
*reply
; 
2097         mach_msg_return_t mr
; 
2099         (void)port
;             // Unused 
2100         (void)size
;             // Unused 
2101         (void)info
;             // Unused 
2103         /* allocate a reply buffer */ 
2104         reply 
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0); 
2106         /* call the MiG server routine */ 
2107         (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
); 
2109         if (!(reply
->Head
.msgh_bits 
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode 
!= KERN_SUCCESS
)) 
2111         if (reply
->RetCode 
== MIG_NO_REPLY
) 
2114              * This return code is a little tricky -- it appears that the 
2115              * demux routine found an error of some sort, but since that 
2116              * error would not normally get returned either to the local 
2117              * user or the remote one, we pretend it's ok. 
2119             CFAllocatorDeallocate(NULL
, reply
); 
2124          * destroy any out-of-line data in the request buffer but don't destroy 
2125          * the reply port right (since we need that to send an error message). 
2127         request
->Head
.msgh_remote_port 
= MACH_PORT_NULL
; 
2128         mach_msg_destroy(&request
->Head
); 
2131     if (reply
->Head
.msgh_remote_port 
== MACH_PORT_NULL
) 
2133         /* no reply port, so destroy the reply */ 
2134         if (reply
->Head
.msgh_bits 
& MACH_MSGH_BITS_COMPLEX
) 
2135             mach_msg_destroy(&reply
->Head
); 
2136         CFAllocatorDeallocate(NULL
, reply
); 
2143      * We don't want to block indefinitely because the client 
2144      * isn't receiving messages from the reply port. 
2145      * If we have a send-once right for the reply port, then 
2146      * this isn't a concern because the send won't block. 
2147      * If we have a send right, we need to use MACH_SEND_TIMEOUT. 
2148      * To avoid falling off the kernel's fast RPC path unnecessarily, 
2149      * we only supply MACH_SEND_TIMEOUT when absolutely necessary. 
2152     options 
= MACH_SEND_MSG
; 
2153     if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
) 
2154         options 
|= MACH_SEND_TIMEOUT
; 
2156     mr 
= mach_msg(&reply
->Head
,         /* msg */ 
2157                       options
,                  /* option */ 
2158                       reply
->Head
.msgh_size
,    /* send_size */ 
2160                       MACH_PORT_NULL
,           /* rcv_name */ 
2161                       MACH_MSG_TIMEOUT_NONE
,    /* timeout */ 
2162                       MACH_PORT_NULL
);          /* notify */ 
2164     /* Has a message error occurred? */ 
2167         case MACH_SEND_INVALID_DEST
: 
2168         case MACH_SEND_TIMED_OUT
: 
2169             /* the reply can't be delivered, so destroy it */ 
2170             mach_msg_destroy(&reply
->Head
); 
2174             /* Includes success case. */ 
2178     CFAllocatorDeallocate(NULL
, reply
); 
2181 mDNSlocal kern_return_t 
registerBootstrapService() 
2183         kern_return_t status
; 
2184         mach_port_t service_send_port
, service_rcv_port
; 
2186         debugf("Registering Bootstrap Service"); 
2189          * See if our service name is already registered and if we have privilege to check in. 
2191         status 
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
); 
2192         if (status 
== KERN_SUCCESS
) 
2195                  * If so, we must be a followup instance of an already defined server.  In that case, 
2196                  * the bootstrap port we inherited from our parent is the server's privilege port, so set 
2197                  * that in case we have to unregister later (which requires the privilege port). 
2199                 server_priv_port 
= bootstrap_port
; 
2200                 restarting_via_mach_init 
= TRUE
; 
2202         else if (status 
== BOOTSTRAP_UNKNOWN_SERVICE
) 
2204                 status 
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(), 
2205                         FALSE 
/* relaunch immediately, not on demand */, &server_priv_port
); 
2206                 if (status 
!= KERN_SUCCESS
) return status
; 
2208                 status 
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
); 
2209                 if (status 
!= KERN_SUCCESS
) 
2211                         mach_port_deallocate(mach_task_self(), server_priv_port
); 
2215                 status 
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
); 
2216                 if (status 
!= KERN_SUCCESS
) 
2218                         mach_port_deallocate(mach_task_self(), server_priv_port
); 
2219                         mach_port_deallocate(mach_task_self(), service_send_port
); 
2222                 assert(service_send_port 
== service_rcv_port
); 
2226          * We have no intention of responding to requests on the service port.  We are not otherwise 
2227          * a Mach port-based service.  We are just using this mechanism for relaunch facilities. 
2228          * So, we can dispose of all the rights we have for the service port.  We don't destroy the 
2229          * send right for the server's privileged bootstrap port - in case we have to unregister later. 
2231         mach_port_destroy(mach_task_self(), service_rcv_port
); 
2235 mDNSlocal kern_return_t 
destroyBootstrapService() 
2237         debugf("Destroying Bootstrap Service"); 
2238         return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
); 
2241 mDNSlocal 
void ExitCallback(int signal
) 
2243         LogMsgIdent(mDNSResponderVersionString
, "stopping"); 
2245         debugf("ExitCallback"); 
2246         if (!mDNS_DebugMode 
&& !started_via_launchdaemon 
&& signal 
!= SIGHUP
) 
2247                 destroyBootstrapService(); 
2249         debugf("ExitCallback: Aborting MIG clients"); 
2250         while (DNSServiceDomainEnumerationList
) 
2251                 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
); 
2252         while (DNSServiceBrowserList
) 
2253                 AbortClient(DNSServiceBrowserList          
->ClientMachPort
, DNSServiceBrowserList
); 
2254         while (DNSServiceResolverList
) 
2255                 AbortClient(DNSServiceResolverList         
->ClientMachPort
, DNSServiceResolverList
); 
2256         while (DNSServiceRegistrationList
) 
2257                 AbortClient(DNSServiceRegistrationList     
->ClientMachPort
, DNSServiceRegistrationList
); 
2259         debugf("ExitCallback: mDNS_Close"); 
2260         mDNS_Close(&mDNSStorage
); 
2261         if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed"); 
2265 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit 
2266 mDNSlocal 
void HandleSIG(int signal
) 
2269         debugf("HandleSIG %d", signal
); 
2270         mach_msg_header_t header
; 
2271         header
.msgh_bits 
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0); 
2272         header
.msgh_remote_port 
= signal_port
; 
2273         header
.msgh_local_port 
= MACH_PORT_NULL
; 
2274         header
.msgh_size 
= sizeof(header
); 
2275         header
.msgh_id 
= signal
; 
2276         if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
) 
2278                 LogMsg("HandleSIG %d: mach_msg_send failed", signal
); 
2279                 if (signal 
== SIGHUP 
|| signal 
== SIGTERM 
|| signal 
== SIGINT
) exit(-1); 
2283 mDNSlocal 
void INFOCallback(void) 
2285         mDNSs32 utc 
= mDNSPlatformUTC(); 
2286         DNSServiceDomainEnumeration 
*e
; 
2287         DNSServiceBrowser           
*b
; 
2288         DNSServiceResolver          
*l
; 
2289         DNSServiceRegistration      
*r
; 
2290         NetworkInterfaceInfoOSX     
*i
; 
2292         LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----"); 
2294         udsserver_info(&mDNSStorage
); 
2296         for (e 
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
) 
2297                 LogMsgNoIdent("%5d: Mach DomainEnumeration   %##s", e
->ClientMachPort
, e
->dom
.qname
.c
); 
2299         for (b 
= DNSServiceBrowserList
; b
; b
=b
->next
) 
2301                 DNSServiceBrowserQuestion 
*qptr
; 
2302                 for (qptr 
= b
->qlist
; qptr
; qptr 
= qptr
->next
) 
2303                         LogMsgNoIdent("%5d: Mach ServiceBrowse       %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
); 
2305         for (l 
= DNSServiceResolverList
; l
; l
=l
->next
) 
2306                 LogMsgNoIdent("%5d: Mach ServiceResolve      %##s", l
->ClientMachPort
, l
->i
.name
.c
); 
2308         for (r 
= DNSServiceRegistrationList
; r
; r
=r
->next
) 
2310                 ServiceInstance 
*si
; 
2311                 for (si 
= r
->regs
; si
; si 
= si
->next
) 
2312                         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
)); 
2315         for (i 
= mDNSStorage
.p
->InterfaceList
; i
; i 
= i
->next
) 
2318                         LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d", 
2319                                 i
->sa_family 
== AF_INET 
? "v4" : i
->sa_family 
== AF_INET6 
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, utc 
- i
->LastSeen
); 
2321                         LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a", 
2322                                 i
->sa_family 
== AF_INET 
? "v4" : i
->sa_family 
== AF_INET6 
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, 
2323                                 i
->ifinfo
.InterfaceActive 
? "Active" : "      ", 
2324                                 i
->ifinfo
.IPv4Available 
? "v4" : "  ", i
->ss
.sktv4
, 
2325                                 i
->ifinfo
.IPv6Available 
? "v6" : "  ", i
->ss
.sktv6
, 
2326                                 i
->ifinfo
.InterfaceID
, 
2327                                 i
->ifinfo
.Advertise 
? "Adv"  : "   ", 
2328                                 i
->ifinfo
.McastTxRx 
? "TxRx" : "    ", 
2332         LogMsgIdent(mDNSResponderVersionString
, "----  END STATE LOG  ----"); 
2335 mDNSlocal 
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
) 
2337         (void)port
;             // Unused 
2338         (void)size
;             // Unused 
2339         (void)info
;             // Unused 
2340         mach_msg_header_t 
*m 
= (mach_msg_header_t 
*)msg
; 
2345                 case SIGTERM
:   ExitCallback(m
->msgh_id
); break; 
2346                 case SIGINFO
:   INFOCallback(); break; 
2347                 case SIGUSR1
:   LogMsg("SIGUSR1: Simulate Network Configuration Change Event"); 
2348                                                 mDNSMacOSXNetworkChanged(&mDNSStorage
); break; 
2349                 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break; 
2353 // On 10.2 the MachServerName is DNSServiceDiscoveryServer 
2354 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder 
2356 mDNSlocal kern_return_t 
mDNSDaemonInitialize(void) 
2359         CFMachPortRef      d_port 
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
); 
2360         CFMachPortRef      s_port 
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
); 
2361         CFMachPortRef      i_port 
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
); 
2362         mach_port_t        m_port 
= CFMachPortGetPort(s_port
); 
2363         char *MachServerName 
= OSXVers 
< 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder"; 
2364         kern_return_t      status 
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
); 
2365         CFRunLoopSourceRef d_rls  
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0); 
2366         CFRunLoopSourceRef s_rls  
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0); 
2367         CFRunLoopSourceRef i_rls  
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0); 
2372                         LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running"); 
2374                         LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
); 
2378         err 
= mDNS_Init(&mDNSStorage
, &PlatformStorage
, 
2379                 rrcachestorage
, RR_CACHE_SIZE
, 
2380                 mDNS_Init_AdvertiseLocalAddresses
, 
2381                 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
); 
2383         if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); } 
2385         gNotificationUserHostLabel 
= gNotificationPrefHostLabel 
= PlatformStorage
.userhostlabel
; 
2386         gNotificationUserNiceLabel 
= gNotificationPrefNiceLabel 
= PlatformStorage
.usernicelabel
; 
2388         client_death_port 
= CFMachPortGetPort(d_port
); 
2389         signal_port 
= CFMachPortGetPort(i_port
); 
2391         CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
); 
2392         CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
); 
2393         CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
); 
2397         if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
); 
2401 mDNSlocal mDNSs32 
mDNSDaemonIdle(mDNS 
*const m
) 
2403         mDNSs32 now 
= mDNS_TimeNow(m
); 
2405         // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute() 
2407         // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost. 
2408         // mDNS_Execute() generates packets, including multicasts that are looped back to ourself. 
2409         // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards 
2410         // we then systematically lose our own looped-back packets. 
2411         if (m
->p
->NetworkChanged 
&& now 
- m
->p
->NetworkChanged 
>= 0) mDNSMacOSXNetworkChanged(m
); 
2413         // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do 
2414         mDNSs32 nextevent 
= mDNS_Execute(m
); 
2416         if (m
->p
->NetworkChanged
) 
2417                 if (nextevent 
- m
->p
->NetworkChanged 
> 0) 
2418                         nextevent 
= m
->p
->NetworkChanged
; 
2420         // 3. Deliver any waiting browse messages to clients 
2421         DNSServiceBrowser 
*b 
= DNSServiceBrowserList
; 
2425                 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the 
2426                 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient() 
2427                 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns 
2428                 DNSServiceBrowser 
*x 
= b
; 
2430                 if (x
->results
)                 // Try to deliver the list of results 
2434                                 DNSServiceBrowserResult 
*const r 
= x
->results
; 
2436                                 domainname type
, domain
; 
2437                                 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
);      // Don't need to check result; already validated in FoundInstance() 
2438                                 char cname
[MAX_DOMAIN_LABEL
+1];                 // Unescaped name: up to 63 bytes plus C-string terminating NULL. 
2439                                 char ctype
[MAX_ESCAPED_DOMAIN_NAME
]; 
2440                                 char cdom 
[MAX_ESCAPED_DOMAIN_NAME
]; 
2441                                 ConvertDomainLabelToCString_unescaped(&name
, cname
); 
2442                                 ConvertDomainNameToCString(&type
, ctype
); 
2443                                 ConvertDomainNameToCString(&domain
, cdom
); 
2444                                 DNSServiceDiscoveryReplyFlags flags 
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing 
: 0; 
2445                                 kern_return_t status 
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1); 
2446                                 // If we failed to send the mach message, try again in one second 
2447                                 if (status 
== MACH_SEND_TIMED_OUT
) 
2449                                         if (nextevent 
- now 
> mDNSPlatformOneSecond
) 
2450                                                 nextevent 
= now 
+ mDNSPlatformOneSecond
; 
2455                                         x
->lastsuccess 
= now
; 
2456                                         x
->results 
= x
->results
->next
; 
2457                                         freeL("DNSServiceBrowserResult", r
); 
2460                         // If this client hasn't read a single message in the last 60 seconds, abort it 
2461                         if (now 
- x
->lastsuccess 
>= 60 * mDNSPlatformOneSecond
) 
2462                                 AbortBlockedClient(x
->ClientMachPort
, "browse", x
); 
2466         DNSServiceResolver 
*l
; 
2467         for (l 
= DNSServiceResolverList
; l
; l
=l
->next
) 
2468                 if (l
->ReportTime 
&& now 
- l
->ReportTime 
>= 0) 
2471                         LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. " 
2472                                 "This places considerable burden on the network.", l
->i
.name
.c
); 
2475         if (m
->p
->NotifyUser
) 
2477                 if (m
->p
->NotifyUser 
- now 
< 0) 
2479                         if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
)) 
2481                                 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
); 
2482                                 gNotificationPrefNiceLabel 
= m
->p
->usernicelabel 
= m
->nicelabel
; 
2483                                 RecordUpdatedName(m
, &gNotificationUserNiceLabel
, &gNotificationPrefNiceLabel
, "The name of your computer", "", 
2484                                         CFSTR("To change the name of your computer, open System Preferences and click Sharing.  " 
2485                                                         "Then type the name in the Computer Name field.")); 
2486                                 // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts 
2487                                 m
->p
->NotifyUser 
= 0; 
2489                         if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
)) 
2491                                 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
); 
2492                                 gNotificationPrefHostLabel 
= m
->p
->userhostlabel 
= m
->hostlabel
; 
2493                                 RecordUpdatedName(m
, &gNotificationUserHostLabel
, &gNotificationPrefHostLabel
, "This computer’s local hostname", ".local", 
2494                                         CFSTR("To change the local hostname, open System Preferences and click Sharing.  " 
2495                                                         "Then click Edit and type the name in the Local Hostname field.")); 
2497                         m
->p
->NotifyUser 
= 0; 
2500                         if (nextevent 
- m
->p
->NotifyUser 
> 0) 
2501                                 nextevent 
= m
->p
->NotifyUser
; 
2507 mDNSlocal 
void ShowTaskSchedulingError(mDNS 
*const m
) 
2511         LogMsg("Task Scheduling Error: Continuously busy for more than a second"); 
2513         if (m
->NewQuestions 
&& (!m
->NewQuestions
->DelayAnswering 
|| m
->timenow 
- m
->NewQuestions
->DelayAnswering 
>= 0)) 
2514                 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)", 
2515                         m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
)); 
2516         if (m
->NewLocalOnlyQuestions
) 
2517                 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)", 
2518                         m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
)); 
2519         if (m
->NewLocalRecords 
&& LocalRecordReady(m
->NewLocalRecords
)) 
2520                 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
)); 
2521         if (m
->SuppressSending 
&& m
->timenow 
- m
->SuppressSending 
>= 0) 
2522                 LogMsg("Task Scheduling Error: m->SuppressSending %d",       m
->timenow 
- m
->SuppressSending
); 
2523 #ifndef UNICAST_DISABLED 
2524         if (m
->timenow 
- m
->uDNS_info
.nextevent   
>= 0) 
2525                 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d",   m
->timenow 
- m
->uDNS_info
.nextevent
); 
2527         if (m
->timenow 
- m
->NextCacheCheck        
>= 0) 
2528                 LogMsg("Task Scheduling Error: m->NextCacheCheck %d",        m
->timenow 
- m
->NextCacheCheck
); 
2529         if (m
->timenow 
- m
->NextScheduledQuery    
>= 0) 
2530                 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d",    m
->timenow 
- m
->NextScheduledQuery
); 
2531         if (m
->timenow 
- m
->NextScheduledProbe    
>= 0) 
2532                 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d",    m
->timenow 
- m
->NextScheduledProbe
); 
2533         if (m
->timenow 
- m
->NextScheduledResponse 
>= 0) 
2534                 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow 
- m
->NextScheduledResponse
); 
2536         mDNS_Unlock(&mDNSStorage
); 
2539 mDNSexport 
int main(int argc
, char **argv
) 
2542         kern_return_t status
; 
2544         for (i
=1; i
<argc
; i
++) 
2546                 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode 
= mDNStrue
; 
2547                 if (!strcmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon 
= mDNStrue
; 
2550         signal(SIGHUP
,  HandleSIG
);             // (Debugging) Exit cleanly and let mach_init restart us (for debugging) 
2551         signal(SIGINT
,  HandleSIG
);             // Ctrl-C: Detach from Mach BootstrapService and exit cleanly 
2552         signal(SIGPIPE
, SIG_IGN  
);             // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly 
2553         signal(SIGTERM
, HandleSIG
);             // Machine shutting down: Detach from and exit cleanly like Ctrl-C 
2554         signal(SIGINFO
, HandleSIG
);             // (Debugging) Write state snapshot to syslog 
2555         signal(SIGUSR1
, HandleSIG
);             // (Debugging) Simulate network change notification from System Configuration Framework 
2557         // Register the server with mach_init for automatic restart only during normal (non-debug) mode 
2558     if (!mDNS_DebugMode 
&& !started_via_launchdaemon
) 
2560         registerBootstrapService(); 
2561         if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon 
2562                 int fd 
= open(_PATH_DEVNULL
, O_RDWR
, 0); 
2563                 if (fd 
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
)); 
2566                         // Avoid unnecessarily duplicating a file descriptor to itself 
2567                         if (fd 
!= STDIN_FILENO
)  if (dup2(fd
, STDIN_FILENO
)  < 0) LogMsg("dup2(fd, STDIN_FILENO)  failed errno %d (%s)", errno
, strerror(errno
)); 
2568                         if (fd 
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
)); 
2569                         if (fd 
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
)); 
2570                         if (fd 
!= STDIN_FILENO 
&& fd 
!= STDOUT_FILENO 
&& fd 
!= STDERR_FILENO
) (void)close(fd
); 
2574         // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons. 
2575         // The sooner we do this, the faster the machine will boot. 
2576         status 
= udsserver_init(); 
2577         if (status
) { LogMsg("Daemon start: udsserver_init failed"); goto exit
; } 
2579         // First do the all the initialization we need root privilege for, before we change to user "nobody" 
2580         LogMsgIdent(mDNSResponderVersionString
, "starting"); 
2581         OSXVers 
= mDNSMacOSXSystemBuildNumber(NULL
); 
2582         status 
= mDNSDaemonInitialize(); 
2584 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT 
2585         // Now that we're finished with anything privileged, switch over to running as "nobody" 
2586         const struct passwd 
*pw 
= getpwnam("nobody"); 
2590                 setuid(-2);             // User "nobody" is -2; use that value if "nobody" does not appear in the password database 
2595                 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
); 
2597                 int RunLoopStatus 
= kCFRunLoopRunTimedOut
; 
2599                 // This is the main work loop: 
2600                 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time 
2601                 // (2) Then we make sure we've delivered all waiting browse messages to our clients 
2602                 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner 
2603                 // (4) On wakeup we first process *all* events 
2604                 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again 
2605                 while (RunLoopStatus 
== kCFRunLoopRunTimedOut
) 
2607                         // 1. Before going into a blocking wait call and letting our process to go sleep, 
2608                         // call mDNSDaemonIdle to allow any deferred work to be completed. 
2609                         mDNSs32 nextevent 
= mDNSDaemonIdle(&mDNSStorage
); 
2610                         nextevent 
= udsserver_idle(nextevent
); 
2612                         // 2. Work out how long we expect to sleep before the next scheduled task 
2613                         mDNSs32 ticks 
= nextevent 
- mDNS_TimeNow(&mDNSStorage
); 
2614                         static mDNSs32 RepeatedBusy 
= 0;        // Debugging sanity check, to guard against CPU spins 
2620                                 if (++RepeatedBusy 
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy 
= 0; } 
2622                         CFAbsoluteTime interval 
= (CFAbsoluteTime
)ticks 
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
; 
2624                         // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until 
2625                         // (a) our next wakeup time, or (b) an event occurs. 
2626                         // The 'true' parameter makes it return after handling any event that occurs 
2627                         // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again 
2628                         verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
); 
2630                         RunLoopStatus 
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true); 
2632                         // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle() 
2633                         while (RunLoopStatus 
== kCFRunLoopRunHandledSource
) 
2636                                 RunLoopStatus 
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true); 
2640                 LogMsg("ERROR: CFRunLoopRun Exiting."); 
2641                 mDNS_Close(&mDNSStorage
); 
2644         LogMsgIdent(mDNSResponderVersionString
, "exiting"); 
2647         if (!mDNS_DebugMode 
&& !started_via_launchdaemon
) destroyBootstrapService(); 
2651 //              uds_daemon.c support routines           ///////////////////////////////////////////// 
2653 // We keep a list of client-supplied event sources in PosixEventSource records 
2654 struct CFSocketEventSource
 
2656         udsEventCallback                        Callback
; 
2659         struct  CFSocketEventSource     
*Next
; 
2661         CFRunLoopSourceRef                      RLS
; 
2663 typedef struct CFSocketEventSource      CFSocketEventSource
; 
2665 static GenLinkedList    gEventSources
;                  // linked list of CFSocketEventSource's 
2667 mDNSlocal 
void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
) 
2668         // Called by CFSocket when data appears on socket 
2674         CFSocketEventSource     
*source 
= (CFSocketEventSource
*) i
; 
2675         source
->Callback(source
->Context
); 
2678 mStatus 
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
) 
2679         // Arrange things so that callback is called with context when data appears on fd 
2681         CFSocketEventSource     
*newSource
; 
2682         CFSocketContext cfContext 
=     { 0, NULL
, NULL
, NULL
, NULL     
}; 
2684         if (gEventSources
.LinkOffset 
== 0) 
2685                 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
)); 
2687         if (fd 
>= FD_SETSIZE 
|| fd 
< 0) 
2688                 return mStatus_UnsupportedErr
; 
2689         if (callback 
== NULL
) 
2690                 return mStatus_BadParamErr
; 
2692         newSource 
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
); 
2693         if (NULL 
== newSource
) 
2694                 return mStatus_NoMemoryErr
; 
2696         newSource
->Callback 
= callback
; 
2697         newSource
->Context 
= context
; 
2700         cfContext
.info 
= newSource
; 
2701         if ( NULL 
!= (newSource
->cfs 
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
, 
2702                                                                                                                                         cf_callback
, &cfContext
)) && 
2703                  NULL 
!= (newSource
->RLS 
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0))) 
2705                 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
); 
2706                 AddToTail(&gEventSources
, newSource
); 
2712                         CFSocketInvalidate(newSource
->cfs
);             // Note: Also closes the underlying socket 
2713                         CFRelease(newSource
->cfs
); 
2715                 return mStatus_NoMemoryErr
; 
2718         return mStatus_NoError
; 
2721 mStatus 
udsSupportRemoveFDFromEventLoop(int fd
)         // Note: This also CLOSES the file descriptor 
2722         // Reverse what was done in udsSupportAddFDToEventLoop(). 
2724         CFSocketEventSource     
*iSource
; 
2726         for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource 
= iSource
->Next
) 
2728                 if (fd 
== iSource
->fd
) 
2730                         RemoveFromList(&gEventSources
, iSource
); 
2731                         CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
); 
2732                         CFRunLoopSourceInvalidate(iSource
->RLS
); 
2733                         CFRelease(iSource
->RLS
); 
2734                         CFSocketInvalidate(iSource
->cfs
);               // Note: Also closes the underlying socket 
2735                         CFRelease(iSource
->cfs
); 
2737                         return mStatus_NoError
; 
2740         return mStatus_NoSuchNameErr
; 
2743 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log 
2744 const char *__crashreporter_info__ 
= mDNSResponderVersionString
; 
2745 asm(".desc ___crashreporter_info__, 0x10"); 
2747 // For convenience when using the "strings" command, this is the last thing in the file 
2748 mDNSexport 
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__ 
" " __TIME__ 
")";