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.244 2005/01/28 00:34:49 cheshire
40 Turn off "Starting time value" log message
42 Revision 1.243 2005/01/27 17:46:58 cheshire
43 Added comment about CFSocketInvalidate closing the underlying socket
45 Revision 1.242 2005/01/27 00:10:58 cheshire
46 <rdar://problem/3967867> Name change log messages every time machine boots
48 Revision 1.241 2005/01/25 17:28:06 ksekar
49 <rdar://problem/3971467> Should not return "local" twice for domain enumeration
51 Revision 1.240 2005/01/21 02:39:18 cheshire
52 Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
54 Revision 1.239 2005/01/20 00:25:01 cheshire
55 Improve validatelists() log message generation
57 Revision 1.238 2005/01/19 19:15:35 ksekar
58 Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
60 Revision 1.237 2005/01/19 03:33:09 cheshire
61 <rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
63 Revision 1.236 2005/01/19 03:16:38 cheshire
64 <rdar://problem/3961051> CPU Spin in mDNSResponder
65 Improve detail of "Task Scheduling Error" diagnostic messages
67 Revision 1.235 2005/01/15 00:56:41 ksekar
68 <rdar://problem/3954575> Unicast services don't disappear when logging
71 Revision 1.234 2005/01/10 03:42:30 ksekar
74 Revision 1.233 2004/12/18 00:53:46 cheshire
75 Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
77 Revision 1.232 2004/12/17 23:37:48 cheshire
78 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
79 (and other repetitive configuration changes)
81 Revision 1.231 2004/12/17 04:13:38 cheshire
82 Removed debugging check
84 Revision 1.230 2004/12/17 04:09:30 cheshire
85 <rdar://problem/3191011> Switch mDNSResponder to launchd
87 Revision 1.229 2004/12/16 21:51:36 cheshire
88 Remove some startup messages
90 Revision 1.228 2004/12/16 20:13:01 cheshire
91 <rdar://problem/3324626> Cache memory management improvements
93 Revision 1.227 2004/12/10 13:52:57 cheshire
94 <rdar://problem/3909995> Turn off SIGPIPE signals
96 Revision 1.226 2004/12/10 05:27:26 cheshire
97 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
99 Revision 1.225 2004/12/10 04:28:29 cheshire
100 <rdar://problem/3914406> User not notified of name changes for services using new UDS API
102 Revision 1.224 2004/12/10 00:41:05 cheshire
103 Adjust alignment of log messages
105 Revision 1.223 2004/12/07 20:42:34 cheshire
106 Add explicit context parameter to mDNS_RemoveRecordFromService()
108 Revision 1.222 2004/12/06 21:15:23 ksekar
109 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
111 Revision 1.221 2004/11/30 03:24:04 cheshire
112 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
114 Revision 1.220 2004/11/29 23:34:31 cheshire
115 On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
116 is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
117 only nudges the time value to 1 if the interval calculation happens to result in the value zero.
119 Revision 1.219 2004/11/25 01:00:56 cheshire
120 Checkin 1.217 not necessary
122 Revision 1.218 2004/11/24 20:27:19 cheshire
123 Add missing "err" parameter in LogMsg() call
125 Revision 1.217 2004/11/24 17:55:01 ksekar
126 Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
128 Revision 1.216 2004/11/24 00:10:44 cheshire
129 <rdar://problem/3869241> For unicast operations, verify that service types are legal
131 Revision 1.215 2004/11/23 22:33:01 cheshire
132 <rdar://problem/3654910> Remove temporary workaround code for iChat
134 Revision 1.214 2004/11/23 22:13:59 cheshire
135 <rdar://problem/3886293> Subtype advertising broken for Mach API
137 Revision 1.213 2004/11/23 06:12:55 cheshire
138 <rdar://problem/3871405> Update wording for name conflict dialogs
140 Revision 1.212 2004/11/23 05:15:37 cheshire
141 <rdar://problem/3875830> Computer Name in use message garbled
143 Revision 1.211 2004/11/23 05:00:41 cheshire
144 <rdar://problem/3874629> Name conflict log message should not have ".local" appended
146 Revision 1.210 2004/11/03 03:45:17 cheshire
147 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
149 Revision 1.209 2004/11/03 02:25:50 cheshire
150 <rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
152 Revision 1.208 2004/11/03 01:54:14 cheshire
153 Update debugging messages
155 Revision 1.207 2004/11/02 23:58:19 cheshire
156 <rdar://problem/2974905> mDNSResponder does not inform user of name collisions
158 Revision 1.206 2004/10/28 02:40:47 cheshire
159 Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
161 Revision 1.205 2004/10/28 02:21:01 cheshire
162 <rdar://problem/3856500> Improve mDNSResponder signal handling
163 Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
164 Added SIGUSR1 to simulate a network change notification from System Configuration Framework
166 Revision 1.204 2004/10/27 01:57:21 cheshire
167 Add check of m->p->InterfaceList
169 Revision 1.203 2004/10/26 04:31:44 cheshire
170 Rename CountSubTypes() as ChopSubTypes()
172 Revision 1.202 2004/10/26 01:29:18 cheshire
173 Use "#if 0" instead of commenting out code
175 Revision 1.201 2004/10/25 21:41:39 ksekar
176 <rdar://problem/3852958> wide-area name conflicts can cause crash
178 Revision 1.200 2004/10/22 01:03:55 cheshire
179 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
180 Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
182 Revision 1.199 2004/10/19 21:33:19 cheshire
183 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
184 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
185 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
187 Revision 1.198 2004/10/15 23:00:18 ksekar
188 <rdar://problem/3799242> Need to update LLQs on location changes
190 Revision 1.197 2004/10/12 23:38:59 ksekar
191 <rdar://problem/3837065> remove unnecessary log message
193 Revision 1.196 2004/10/04 05:56:04 cheshire
194 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
196 Revision 1.195 2004/09/30 00:24:59 ksekar
197 <rdar://problem/3695802> Dynamically update default registration domains on config change
199 Revision 1.194 2004/09/26 23:20:35 ksekar
200 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
202 Revision 1.193 2004/09/23 23:35:27 cheshire
205 Revision 1.192 2004/09/21 23:40:12 ksekar
206 <rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
208 Revision 1.191 2004/09/21 21:05:12 cheshire
209 Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
210 into mDNSShared/uds_daemon.c
212 Revision 1.190 2004/09/21 19:51:15 cheshire
213 Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
215 Revision 1.189 2004/09/21 18:17:23 cheshire
216 <rdar://problem/3785400> Add version info to mDNSResponder
218 Revision 1.188 2004/09/20 21:45:27 ksekar
221 Revision 1.187 2004/09/17 01:08:52 cheshire
222 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
223 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
224 declared in that file are ONLY appropriate to single-address-space embedded applications.
225 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
227 Revision 1.186 2004/09/16 00:24:49 cheshire
228 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
230 Revision 1.185 2004/08/25 02:01:45 cheshire
231 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
233 Revision 1.184 2004/08/19 19:04:12 ksekar
234 <rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
236 Revision 1.183 2004/08/14 03:22:42 cheshire
237 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
238 Add GetUserSpecifiedDDNSName() routine
239 Convert ServiceRegDomain to domainname instead of C string
240 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
242 Revision 1.182 2004/08/13 23:57:59 cheshire
243 Get rid of non-portable "_UNUSED"
245 Revision 1.181 2004/08/11 02:02:26 cheshire
246 Remove "mDNS *globalInstance" parameter from udsserver_init();
247 Move CheckForDuplicateRegistrations to uds_daemon.c
249 Revision 1.180 2004/07/13 21:24:25 rpantos
250 Fix for <rdar://problem/3701120>.
252 Revision 1.179 2004/06/19 00:02:54 cheshire
253 Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
255 Revision 1.178 2004/06/18 19:10:00 cheshire
256 <rdar://problem/3588761> Current method of doing subtypes causes name collisions
258 Revision 1.177 2004/06/16 23:14:46 ksekar
259 <rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
261 Revision 1.176 2004/06/11 20:27:42 cheshire
262 Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
264 Revision 1.175 2004/06/10 20:23:21 cheshire
265 Also list interfaces in SIGINFO output
267 Revision 1.174 2004/06/08 18:54:48 ksekar
268 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
270 Revision 1.173 2004/06/08 17:35:12 cheshire
271 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
273 Revision 1.172 2004/06/05 00:04:26 cheshire
274 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
276 Revision 1.171 2004/06/04 08:58:30 ksekar
277 <rdar://problem/3668624>: Keychain integration for secure dynamic update
279 Revision 1.170 2004/05/30 20:01:50 ksekar
280 <rdar://problem/3668635>: wide-area default registrations should be in
281 .local too - fixed service registration when clients pass an explicit
282 domain (broken by previous checkin)
284 Revision 1.169 2004/05/30 01:30:16 ksekar
285 <rdar://problem/3668635>: wide-area default registrations should be in
288 Revision 1.168 2004/05/18 23:51:26 cheshire
289 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
291 Revision 1.167 2004/05/14 16:39:47 ksekar
292 Browse for iChat locally for now.
294 Revision 1.166 2004/05/13 21:33:52 ksekar
295 Clean up non-local registration control via config file. Force iChat
296 registrations to be local for now.
298 Revision 1.165 2004/05/13 04:54:20 ksekar
299 Unified list copy/free code. Added symetric list for
301 Revision 1.164 2004/05/12 22:03:08 ksekar
302 Made GetSearchDomainList a true platform-layer call (declaration moved
303 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
304 only on non-OSX platforms. Changed call to return a copy of the list
305 to avoid shared memory issues. Added a routine to free the list.
307 Revision 1.163 2004/05/12 02:03:25 ksekar
308 Non-local domains will only be browsed by default, and show up in
309 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
311 Revision 1.162 2004/04/14 23:09:29 ksekar
312 Support for TSIG signed dynamic updates.
314 Revision 1.161 2004/04/07 01:20:04 cheshire
315 Hash slot value should be unsigned
317 Revision 1.160 2004/04/06 19:51:24 cheshire
318 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
319 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
321 Revision 1.159 2004/04/03 01:36:55 cheshire
322 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
323 If "nobody" user doesn't exist, log a message and continue as "root"
325 Revision 1.158 2004/04/02 21:39:05 cheshire
326 Fix errors in comments
328 Revision 1.157 2004/03/19 18:49:10 ksekar
329 Increased size check in freeL() to account for LargeCacheRecord
330 structs larger than 8k
332 Revision 1.156 2004/03/19 18:19:19 ksekar
333 Fixed daemon.c to compile with malloc debugging turned on.
335 Revision 1.155 2004/03/13 01:57:34 ksekar
336 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
338 Revision 1.154 2004/03/12 08:42:47 cheshire
339 <rdar://problem/3548256>: Should not allow empty string for resolve domain
341 Revision 1.153 2004/03/12 08:08:51 cheshire
344 Revision 1.152 2004/02/05 19:39:29 cheshire
345 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
346 so that all platforms get this functionality
348 Revision 1.151 2004/02/03 22:35:34 cheshire
349 <rdar://problem/3548256>: Should not allow empty string for resolve domain
351 Revision 1.150 2004/01/28 21:14:23 cheshire
352 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
354 Revision 1.149 2004/01/28 02:30:08 ksekar
355 Added default Search Domains to unicast browsing, controlled via
356 Networking sharing prefs pane. Stopped sending unicast messages on
357 every interface. Fixed unicast resolving via mach-port API.
359 Revision 1.148 2004/01/25 00:03:20 cheshire
360 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
362 Revision 1.147 2004/01/19 19:51:46 cheshire
363 Fix compiler error (mixed declarations and code) on some versions of Linux
365 Revision 1.146 2003/12/08 21:00:46 rpantos
366 Changes to support mDNSResponder on Linux.
368 Revision 1.145 2003/12/05 22:08:07 cheshire
369 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
371 Revision 1.144 2003/11/19 23:21:08 ksekar
372 <rdar://problem/3486646>: config change handler not called for dns-sd services
374 Revision 1.143 2003/11/14 21:18:32 cheshire
375 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
376 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
378 Revision 1.142 2003/11/08 22:18:29 cheshire
379 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
381 Revision 1.141 2003/11/07 02:30:57 cheshire
382 Also check per-slot cache use counts in SIGINFO state log
384 Revision 1.140 2003/10/21 19:58:26 cheshire
385 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
387 Revision 1.139 2003/10/21 00:10:18 rpantos
388 <rdar://problem/3409401>: mDNSResponder should not run as root
390 Revision 1.138 2003/10/07 20:16:58 cheshire
391 Shorten syslog message a bit
393 Revision 1.137 2003/09/23 02:12:43 cheshire
394 Also include port number in list of services registered via new UDS API
396 Revision 1.136 2003/09/23 02:07:25 cheshire
397 Include port number in DNSServiceRegistration START/STOP messages
399 Revision 1.135 2003/09/23 01:34:02 cheshire
400 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
402 Revision 1.134 2003/08/21 20:01:37 cheshire
403 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
405 Revision 1.133 2003/08/20 23:39:31 cheshire
406 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
408 Revision 1.132 2003/08/20 01:44:56 cheshire
409 Fix errors in LogOperation() calls (only used for debugging)
411 Revision 1.131 2003/08/19 05:39:43 cheshire
412 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
414 Revision 1.130 2003/08/16 03:39:01 cheshire
415 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
417 Revision 1.129 2003/08/15 20:16:03 cheshire
418 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
419 We want to avoid touching the rdata pages, so we don't page them in.
420 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
421 Moved this from the RData to the ResourceRecord object.
422 2. To avoid unnecessarily touching the rdata just to compare it,
423 compute a hash of the rdata and store the hash in the ResourceRecord object.
425 Revision 1.128 2003/08/14 19:30:36 cheshire
426 <rdar://problem/3378473> Include list of cache records in SIGINFO output
428 Revision 1.127 2003/08/14 02:18:21 cheshire
429 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
431 Revision 1.126 2003/08/12 19:56:25 cheshire
434 Revision 1.125 2003/08/08 18:36:04 cheshire
435 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
437 Revision 1.124 2003/07/25 18:28:23 cheshire
438 Minor fix to error messages in syslog: Display string parameters with quotes
440 Revision 1.123 2003/07/23 17:45:28 cheshire
441 <rdar://problem/3339388> mDNSResponder leaks a bit
442 Don't allocate memory for the reply until after we've verified that the reply is valid
444 Revision 1.122 2003/07/23 00:00:04 cheshire
447 Revision 1.121 2003/07/20 03:38:51 ksekar
448 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
450 Revision 1.120 2003/07/18 00:30:00 cheshire
451 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
453 Revision 1.119 2003/07/17 19:08:58 cheshire
454 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
456 Revision 1.118 2003/07/15 21:12:28 cheshire
457 Added extra debugging checks in validatelists() (not used in final shipping version)
459 Revision 1.117 2003/07/15 01:55:15 cheshire
460 <rdar://problem/3315777> Need to implement service registration with subtypes
462 Revision 1.116 2003/07/02 21:19:51 cheshire
463 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
465 Revision 1.115 2003/07/02 02:41:24 cheshire
466 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
468 Revision 1.114 2003/07/01 21:10:20 cheshire
469 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
471 Revision 1.113 2003/06/28 17:27:43 vlubet
472 <rdar://problem/3221246> Redirect standard input, standard output, and
473 standard error file descriptors to /dev/null just like any other
476 Revision 1.112 2003/06/25 23:42:19 ksekar
477 <rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
478 Reviewed by: Stuart Cheshire
479 Added files necessary to implement Unix domain sockets based enhanced
480 DNS-SD APIs, and integrated with existing Mach-port based daemon.
482 Revision 1.111 2003/06/11 01:02:43 cheshire
483 <rdar://problem/3287858> mDNSResponder binary compatibility
484 Make single binary that can run on both Jaguar and Panther.
486 Revision 1.110 2003/06/10 01:14:11 cheshire
487 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
489 Revision 1.109 2003/06/06 19:53:43 cheshire
490 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
491 (Global search-and-replace; no functional change to code execution.)
493 Revision 1.108 2003/06/06 14:08:06 cheshire
494 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
496 Revision 1.107 2003/05/29 05:44:55 cheshire
497 Minor fixes to log messages
499 Revision 1.106 2003/05/27 18:30:55 cheshire
500 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
501 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
503 Revision 1.105 2003/05/26 03:21:29 cheshire
504 Tidy up address structure naming:
505 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
506 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
507 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
509 Revision 1.104 2003/05/26 00:42:06 cheshire
510 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
512 Revision 1.103 2003/05/23 23:07:44 cheshire
513 <rdar://problem/3268199> Must not write to stderr when running as daemon
515 Revision 1.102 2003/05/22 01:32:31 cheshire
516 Fix typo in Log message format string
518 Revision 1.101 2003/05/22 00:26:55 cheshire
519 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
520 Modify error message to explain that this is technically legal, but may indicate a bug.
522 Revision 1.100 2003/05/21 21:02:24 ksekar
523 <rdar://problem/3247035>: Service should be prefixed
524 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
525 Mach message port to "com.apple.mDNSResponder.
527 Revision 1.99 2003/05/21 17:33:49 cheshire
528 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
530 Revision 1.98 2003/05/20 00:33:07 cheshire
531 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
532 SIGHUP now writes state summary to syslog
534 Revision 1.97 2003/05/08 00:19:08 cheshire
535 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
537 Revision 1.96 2003/05/07 22:10:46 cheshire
538 <rdar://problem/3250330> Add a few more error logging messages
540 Revision 1.95 2003/05/07 19:20:17 cheshire
541 <rdar://problem/3251391> Add version number to mDNSResponder builds
543 Revision 1.94 2003/05/07 00:28:18 cheshire
544 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
546 Revision 1.93 2003/05/06 00:00:49 cheshire
547 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
549 Revision 1.92 2003/04/04 20:38:57 cheshire
554 #include <mach/mach.h>
555 #include <mach/mach_error.h>
556 #include <servers/bootstrap.h>
557 #include <sys/types.h>
562 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
564 #include "DNSServiceDiscoveryRequestServer.h"
565 #include "DNSServiceDiscoveryReply.h"
567 #include "DNSCommon.h"
568 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
570 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
572 #include "GenLinkedList.h"
574 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
576 //*************************************************************************************************************
579 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
580 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
581 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
582 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
583 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
585 //*************************************************************************************************************
588 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
589 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
590 static mDNS_PlatformSupport PlatformStorage
;
592 // Start off with a default cache of 16K (about 100 records)
593 #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
594 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
596 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
597 static mach_port_t client_death_port
= MACH_PORT_NULL
;
598 static mach_port_t signal_port
= MACH_PORT_NULL
;
599 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
601 // mDNS Mach Message Timeout, in milliseconds.
602 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
603 // fails to service its mach message queue, but long enough to give a well-written
604 // client a chance to service its mach message queue without getting cut off.
605 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
606 // even extra-slow clients a fair chance before we cut them off.
607 #define MDNS_MM_TIMEOUT 250
609 static int restarting_via_mach_init
= 0;
610 static int started_via_launchdaemon
= 0;
612 //*************************************************************************************************************
613 // Active client list structures
615 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
616 struct DNSServiceDomainEnumeration_struct
618 DNSServiceDomainEnumeration
*next
;
619 mach_port_t ClientMachPort
;
620 DNSQuestion dom
; // Question asking for domains
621 DNSQuestion def
; // Question asking for default domain
624 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
625 struct DNSServiceBrowserResult_struct
627 DNSServiceBrowserResult
*next
;
632 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
634 typedef struct DNSServiceBrowserQuestion
636 struct DNSServiceBrowserQuestion
*next
;
639 } DNSServiceBrowserQuestion
;
641 struct DNSServiceBrowser_struct
643 DNSServiceBrowser
*next
;
644 mach_port_t ClientMachPort
;
645 DNSServiceBrowserQuestion
*qlist
;
646 DNSServiceBrowserResult
*results
;
648 mDNSBool DefaultDomain
; // was the browse started on an explicit domain?
649 domainname type
; // registration type
652 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
653 struct DNSServiceResolver_struct
655 DNSServiceResolver
*next
;
656 mach_port_t ClientMachPort
;
662 // A single registered service: ServiceRecordSet + bookkeeping
663 // Note that we duplicate some fields from parent DNSServiceRegistration object
664 // to facilitate cleanup, when instances and parent may be deallocated at different times.
665 typedef struct ServiceInstance
667 struct ServiceInstance
*next
;
668 mach_port_t ClientMachPort
;
669 mDNSBool autoname
; // Set if this name is tied to the Computer Name
670 mDNSBool autorename
; // Set if we just got a name conflict and now need to automatically pick a new name
673 ServiceRecordSet srs
;
674 // Don't add any fields after ServiceRecordSet.
675 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
678 // A client-created service. May reference several ServiceInstance objects if default
679 // settings cause registration in multiple domains.
680 typedef struct DNSServiceRegistration
682 struct DNSServiceRegistration
*next
;
683 mach_port_t ClientMachPort
;
684 mDNSBool DefaultDomain
;
688 char regtype
[MAX_ESCAPED_DOMAIN_NAME
]; // for use in AllocateSubtypes
689 domainlabel name
; // used only if autoname is false
692 unsigned char txtinfo
[1024];
695 ServiceInstance
*regs
;
696 } DNSServiceRegistration
;
698 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
699 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
700 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
701 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
703 //*************************************************************************************************************
704 // General Utility Functions
706 #if MACOSX_MDNS_MALLOC_DEBUGGING
708 char _malloc_options
[] = "AXZ";
710 static void validatelists(mDNS
*const m
)
712 DNSServiceDomainEnumeration
*e
;
713 DNSServiceBrowser
*b
;
714 DNSServiceResolver
*l
;
715 DNSServiceRegistration
*r
;
721 NetworkInterfaceInfoOSX
*i
;
723 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
724 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
725 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
);
727 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
728 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
729 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
);
731 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
732 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
733 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
);
735 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
736 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
737 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
);
739 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
741 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
742 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
743 if (rr
->resrec
.name
!= &rr
->namestorage
)
744 LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
745 rr
, rr
->resrec
.name
->c
, rr
->namestorage
.c
, rr
->namestorage
.c
);
748 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
749 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
750 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
752 for (q
= m
->Questions
; q
; q
=q
->next
)
753 if (q
->ThisQInterval
== (mDNSs32
)~0)
754 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
);
756 FORALL_CACHERECORDS(slot
, cg
, cr
)
757 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
758 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->resrec
.RecordType
);
760 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
762 LogMsg("!!!! InterfaceList: %p is garbage !!!!", i
);
765 void *mallocL(char *msg
, unsigned int size
)
767 unsigned long *mem
= malloc(size
+8);
770 LogMsg("malloc( %s : %d ) failed", msg
, size
);
775 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
778 //bzero(&mem[2], size);
779 memset(&mem
[2], 0xFF, size
);
780 validatelists(&mDNSStorage
);
785 void freeL(char *msg
, void *x
)
788 LogMsg("free( %s @ NULL )!", msg
);
791 unsigned long *mem
= ((unsigned long *)x
) - 2;
792 if (mem
[0] != 0xDEAD1234)
793 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
795 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
796 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
797 //bzero(mem, mem[1]+8);
798 memset(mem
, 0xFF, mem
[1]+8);
799 validatelists(&mDNSStorage
);
806 //*************************************************************************************************************
807 // Client Death Detection
809 mDNSlocal
void FreeServiceInstance(ServiceInstance
*x
)
811 ServiceRecordSet
*s
= &x
->srs
;
812 ExtraResourceRecord
*e
= x
->srs
.Extras
, *tmp
;
816 e
->r
.RecordContext
= e
;
819 FreeExtraRR(&mDNSStorage
, &tmp
->r
, mStatus_MemFree
);
822 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
823 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
825 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
826 freeL("ServiceInstance", x
);
829 // AbortClient finds whatever client is identified by the given Mach port,
830 // stops whatever operation that client was doing, and frees its memory.
831 // In the case of a service registration, the actual freeing may be deferred
832 // until we get the mStatus_MemFree message, if necessary
833 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
835 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
836 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
837 DNSServiceResolver
**l
= &DNSServiceResolverList
;
838 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
840 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
843 DNSServiceDomainEnumeration
*x
= *e
;
846 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
847 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
848 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
849 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
850 freeL("DNSServiceDomainEnumeration", x
);
854 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
857 DNSServiceBrowser
*x
= *b
;
858 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
863 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
864 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
865 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
868 freeL("DNSServiceBrowserQuestion", freePtr
);
872 DNSServiceBrowserResult
*r
= x
->results
;
873 x
->results
= x
->results
->next
;
874 freeL("DNSServiceBrowserResult", r
);
876 freeL("DNSServiceBrowser", x
);
880 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
883 DNSServiceResolver
*x
= *l
;
886 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
887 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
888 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
889 freeL("DNSServiceResolver", x
);
893 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
896 ServiceInstance
*si
= NULL
;
897 DNSServiceRegistration
*x
= *r
;
903 ServiceInstance
*instance
= si
;
905 instance
->autorename
= mDNSfalse
;
906 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
);
907 else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, instance
->srs
.RR_SRV
.resrec
.name
->c
, SRS_PORT(&instance
->srs
));
909 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
910 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
911 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
912 // the list, so we should go ahead and free the memory right now
913 if (mDNS_DeregisterService(&mDNSStorage
, &instance
->srs
)) FreeServiceInstance(instance
); // FreeServiceInstance invalidates pointer
916 freeL("DNSServiceRegistration", x
);
920 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
923 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
925 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
927 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
928 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
929 DNSServiceResolver
*l
= DNSServiceResolverList
;
930 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
931 DNSServiceBrowserQuestion
*qptr
;
933 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
934 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
935 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
936 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
937 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
940 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
941 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
943 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
947 for (si
= r
->regs
; si
; si
= si
->next
) LogMsg("%5d: Registration(%##s) %s%s", c
, si
->srs
.RR_SRV
.resrec
.name
->c
, reason
, msg
);
949 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
954 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
956 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
957 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
958 DNSServiceResolver
*l
= DNSServiceResolverList
;
959 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
960 DNSServiceBrowserQuestion
*qptr
;
962 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
963 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
964 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
965 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
966 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
969 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
970 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
972 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
973 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->regs
? r
->regs
->srs
.RR_SRV
.resrec
.name
->c
: NULL
);
974 return(e
|| b
|| l
|| r
);
977 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
979 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
980 (void)unusedport
; // Unused
981 (void)size
; // Unused
982 (void)info
; // Unused
983 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
985 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
986 AbortClient(deathMessage
->not_port
, NULL
);
988 /* Deallocate the send right that came in the dead name notification */
989 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
993 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
996 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
997 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
998 // If the port already died while we were thinking about it, then abort the operation right away
999 if (r
!= KERN_SUCCESS
)
1000 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
1003 //*************************************************************************************************************
1004 // Domain Enumeration
1006 mDNSlocal
void DomainEnumFound(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1008 kern_return_t status
;
1010 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
1011 DNSServiceDomainEnumerationReplyResultType rt
;
1012 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
1014 debugf("DomainEnumFound: %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1015 if (answer
->rrtype
!= kDNSType_PTR
) return;
1016 if (!x
) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
1020 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
1021 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
1025 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
1029 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
1030 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
1031 !AddRecord
? "RemoveDomain" :
1032 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
1034 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
1035 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
1036 if (status
== MACH_SEND_TIMED_OUT
)
1037 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
1040 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1043 // Check client parameter
1044 (void)unusedserver
; // Unused
1045 mStatus err
= mStatus_NoError
;
1046 const char *errormsg
= "Unknown";
1047 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1048 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1050 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
1051 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
1053 // Allocate memory, and handle failure
1054 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
1055 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1057 // Set up object, and link into list
1058 x
->ClientMachPort
= client
;
1059 x
->next
= DNSServiceDomainEnumerationList
;
1060 DNSServiceDomainEnumerationList
= x
;
1062 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
1065 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1066 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, DomainEnumFound
, x
);
1067 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
1069 // Succeeded: Wrap up and return
1070 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
1071 EnableDeathNotificationForClient(client
, x
);
1072 return(mStatus_NoError
);
1075 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
1079 //*************************************************************************************************************
1080 // Browse for services
1082 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
1086 if (answer
->rrtype
!= kDNSType_PTR
)
1087 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
1090 domainname type
, domain
;
1091 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
1093 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
1094 answer
->name
->c
, answer
->rdata
->u
.name
.c
);
1098 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
1099 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
1101 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
1102 AssignDomainName(&x
->result
, &answer
->rdata
->u
.name
);
1104 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
1105 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
1108 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
1109 DNSServiceBrowserResult
**p
= &browser
->results
;
1110 while (*p
) p
= &(*p
)->next
;
1114 mDNSlocal mStatus
AddDomainToBrowser(DNSServiceBrowser
*browser
, const domainname
*d
)
1116 mStatus err
= mStatus_NoError
;
1117 DNSServiceBrowserQuestion
*ptr
, *question
= NULL
;
1119 for (ptr
= browser
->qlist
; ptr
; ptr
= ptr
->next
)
1121 if (SameDomainName(&ptr
->q
.qname
, d
))
1122 { debugf("Domain %##s already contained in browser", d
->c
); return mStatus_AlreadyRegistered
; }
1125 question
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
1126 if (!question
) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr
; }
1127 AssignDomainName(&question
->domain
, d
);
1128 question
->next
= browser
->qlist
;
1129 browser
->qlist
= question
;
1130 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser
->ClientMachPort
, browser
->type
.c
, d
->c
);
1131 err
= mDNS_StartBrowse(&mDNSStorage
, &question
->q
, &browser
->type
, d
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, browser
);
1132 if (err
) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err
);
1136 mDNSexport
void DefaultBrowseDomainChanged(const domainname
*d
, mDNSBool add
)
1138 DNSServiceBrowser
*ptr
;
1140 debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
1141 for (ptr
= DNSServiceBrowserList
; ptr
; ptr
= ptr
->next
)
1143 if (ptr
->DefaultDomain
)
1147 mStatus err
= AddDomainToBrowser(ptr
, d
);
1148 if (err
&& err
!= mStatus_AlreadyRegistered
) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d
, ptr
->ClientMachPort
);
1152 DNSServiceBrowserQuestion
**q
= &ptr
->qlist
;
1155 if (SameDomainName(&(*q
)->domain
, d
))
1157 DNSServiceBrowserQuestion
*remove
= *q
;
1159 if (remove
->q
.LongLived
)
1161 // give goodbyes for known answers. note that since events are sent to client via udns_execute(),
1162 // we don't need to worry about the question being cancelled mid-loop
1163 CacheRecord
*ka
= remove
->q
.uDNS_info
.knownAnswers
;
1164 while (ka
) { remove
->q
.QuestionCallback(&mDNSStorage
, &remove
->q
, &ka
->resrec
, mDNSfalse
); ka
= ka
->next
; }
1166 mDNS_StopBrowse(&mDNSStorage
, &remove
->q
);
1167 freeL("DNSServiceBrowserQuestion", remove
);
1172 LogMsg("Requested removal of default domain %##s not in client %5d's list", d
->c
, ptr
->ClientMachPort
);
1178 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1179 DNSCString regtype
, DNSCString domain
)
1181 // Check client parameter
1182 (void)unusedserver
; // Unused
1183 mStatus err
= mStatus_NoError
;
1184 const char *errormsg
= "Unknown";
1185 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
1187 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1188 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1190 // Check other parameters
1193 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1194 if (NumSubTypes
< 0 || NumSubTypes
> 1) { errormsg
= "Bad Service SubType"; goto badparam
; }
1195 if (NumSubTypes
== 1 && !AppendDNSNameString(&t
, regtype
+ strlen(regtype
) + 1))
1196 { errormsg
= "Bad Service SubType"; goto badparam
; }
1197 if (!regtype
[0] || !AppendDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1199 if (!MakeDomainNameFromDNSNameString(&temp
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
1200 if (temp
.c
[0] > 15 && (!domain
|| domain
[0] == 0)) domain
= "local."; // For over-long service types, we only allow domain "local"
1202 // Allocate memory, and handle failure
1203 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
1204 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1206 // Set up object, and link into list
1207 AssignDomainName(&x
->type
, &t
);
1208 x
->ClientMachPort
= client
;
1212 x
->next
= DNSServiceBrowserList
;
1213 DNSServiceBrowserList
= x
;
1217 // Start browser for an explicit domain
1218 x
->DefaultDomain
= mDNSfalse
;
1219 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
1220 err
= AddDomainToBrowser(x
, &d
);
1221 if (err
) { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1225 // Start browser on all domains
1226 x
->DefaultDomain
= mDNStrue
;
1227 SearchDomains
= mDNSPlatformGetSearchDomainList();
1228 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
1229 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
1231 err
= AddDomainToBrowser(x
, &sdPtr
->name
);
1234 // only terminally bail if .local fails
1235 if (!SameDomainName(&localdomain
, &sdPtr
->name
))
1236 LogMsg("Default browse in domain %##s failed. Continuing", sdPtr
->name
.c
);
1237 else { AbortClient(client
, x
); errormsg
= "AddDomainToBrowser"; goto fail
; }
1242 // Succeeded: Wrap up and return
1243 EnableDeathNotificationForClient(client
, x
);
1244 mDNS_FreeDNameList(SearchDomains
);
1245 return(mStatus_NoError
);
1248 err
= mStatus_BadParamErr
;
1250 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
1251 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
1255 //*************************************************************************************************************
1256 // Resolve Service Info
1258 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
1260 kern_return_t status
;
1261 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
1262 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
1263 if (query
->info
->InterfaceID
== mDNSInterface_LocalOnly
) ifx
= mDNSNULL
;
1264 struct sockaddr_storage interface
;
1265 struct sockaddr_storage address
;
1267 int i
, pstrlen
= query
->info
->TXTinfo
[0];
1270 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
1272 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
1274 bzero(&interface
, sizeof(interface
));
1275 bzero(&address
, sizeof(address
));
1277 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1279 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1280 sin
->sin_len
= sizeof(*sin
);
1281 sin
->sin_family
= AF_INET
;
1283 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1285 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1287 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1288 sin6
->sin6_len
= sizeof(*sin6
);
1289 sin6
->sin6_family
= AF_INET6
;
1290 sin6
->sin6_flowinfo
= 0;
1291 sin6
->sin6_port
= 0;
1292 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1293 sin6
->sin6_scope_id
= ifx
->scope_id
;
1296 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1298 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1299 sin
->sin_len
= sizeof(*sin
);
1300 sin
->sin_family
= AF_INET
;
1301 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1302 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1306 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1307 sin6
->sin6_len
= sizeof(*sin6
);
1308 sin6
->sin6_family
= AF_INET6
;
1309 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1310 sin6
->sin6_flowinfo
= 0;
1311 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1312 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1315 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1316 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1317 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1318 // ASCII-1 characters are used in the C-string as boundary markers,
1319 // to indicate the boundaries between the original constituent P-strings.
1320 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1323 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1327 pstrlen
= query
->info
->TXTinfo
[i
];
1330 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1332 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1333 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1334 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1335 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1336 if (status
== MACH_SEND_TIMED_OUT
)
1337 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1340 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1341 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1343 // Check client parameter
1344 (void)unusedserver
; // Unused
1345 mStatus err
= mStatus_NoError
;
1346 const char *errormsg
= "Unknown";
1347 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1348 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1350 // Check other parameters
1352 domainname t
, d
, srv
;
1353 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1354 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1355 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1356 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1358 // Allocate memory, and handle failure
1359 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1360 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1362 // Set up object, and link into list
1363 x
->ClientMachPort
= client
;
1364 x
->i
.InterfaceID
= mDNSInterface_Any
;
1366 x
->ReportTime
= NonZeroTime(mDNS_TimeNow(&mDNSStorage
) + 130 * mDNSPlatformOneSecond
);
1367 x
->next
= DNSServiceResolverList
;
1368 DNSServiceResolverList
= x
;
1371 LogOperation("%5d: DNSServiceResolver(%##s) START", client
, x
->i
.name
.c
);
1372 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1373 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1375 // Succeeded: Wrap up and return
1376 EnableDeathNotificationForClient(client
, x
);
1377 return(mStatus_NoError
);
1380 err
= mStatus_BadParamErr
;
1382 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1386 //*************************************************************************************************************
1389 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1391 m
->p
->NotifyUser
= NonZeroTime(m
->timenow
+ delay
);
1394 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
)
1396 ServiceInstance
*si
= (ServiceInstance
*)srs
->ServiceContext
;
1398 if (result
== mStatus_NoError
)
1400 kern_return_t status
;
1401 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1402 status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1403 if (status
== MACH_SEND_TIMED_OUT
)
1404 AbortBlockedClient(si
->ClientMachPort
, "registration success", si
);
1405 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1406 RecordUpdatedNiceLabel(m
, 0); // Successfully got new name, tell user immediately
1409 else if (result
== mStatus_NameConflict
)
1411 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
));
1412 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1413 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1414 if (si
->autoname
&& CountPeerRegistrations(m
, srs
) == 0)
1416 // On conflict for an autoname service, rename and reregister *all* autoname services
1417 IncrementLabelSuffix(&m
->nicelabel
, mDNStrue
);
1418 m
->MainCallback(m
, mStatus_ConfigChanged
);
1420 else if (si
->autoname
)
1422 mDNS_RenameAndReregisterService(m
, srs
, mDNSNULL
);
1427 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1428 // of their registration in the usual way (which we will catch via client death notification).
1429 // If the Mach queue is full, we forcibly abort the client immediately.
1430 kern_return_t status
= DNSServiceRegistrationReply_rpc(si
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1431 if (status
== MACH_SEND_TIMED_OUT
)
1432 AbortBlockedClient(si
->ClientMachPort
, "registration conflict", NULL
);
1436 else if (result
== mStatus_MemFree
)
1440 debugf("RegCallback renaming %#s to %#s", si
->name
.c
, m
->nicelabel
.c
);
1441 si
->autorename
= mDNSfalse
;
1442 si
->name
= m
->nicelabel
;
1443 mDNS_RenameAndReregisterService(m
, srs
, &si
->name
);
1447 // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
1448 DNSServiceRegistration
*r
;
1449 for (r
= DNSServiceRegistrationList
; r
; r
= r
->next
)
1451 ServiceInstance
*sp
= r
->regs
, *prev
= NULL
;
1456 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs
->RR_SRV
.resrec
.name
->c
);
1457 if (prev
) prev
->next
= sp
->next
;
1458 else r
->regs
= sp
->next
;
1466 FreeServiceInstance(si
);
1470 else if (result
!= mStatus_NATTraversal
)
1471 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si
->ClientMachPort
, srs
->RR_SRV
.resrec
.name
->c
, SRS_PORT(srs
), result
);
1474 mDNSlocal mStatus
AddServiceInstance(DNSServiceRegistration
*x
, const domainname
*domain
)
1477 ServiceInstance
*si
= NULL
;
1478 AuthRecord
*SubTypes
= NULL
;
1480 for (si
= x
->regs
; si
; si
= si
->next
)
1482 if (SameDomainName(&si
->domain
, domain
))
1483 { LogMsg("Requested addition of domain %##s already in list", domain
->c
); return mStatus_AlreadyRegistered
; }
1486 SubTypes
= AllocateSubTypes(x
->NumSubTypes
, x
->regtype
);
1487 if (x
->NumSubTypes
&& !SubTypes
) return mStatus_NoMemoryErr
;
1489 si
= mallocL("ServiceInstance", sizeof(*si
) - sizeof(RDataBody
) + x
->rdsize
);
1490 if (!si
) return mStatus_NoMemoryErr
;
1492 si
->ClientMachPort
= x
->ClientMachPort
;
1493 si
->autorename
= mDNSfalse
;
1494 si
->autoname
= x
->autoname
;
1495 si
->name
= x
->autoname
? mDNSStorage
.nicelabel
: x
->name
;
1496 si
->domain
= *domain
;
1498 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
);
1506 LogMsg("Error %d for registration of service in domain %##s", err
, domain
->c
);
1507 freeL("ServiceInstance", si
);
1512 mDNSexport
void DefaultRegDomainChanged(const domainname
*d
, mDNSBool add
)
1514 DNSServiceRegistration
*reg
;
1516 LogMsg("%s default registration domain %##s", add
? "Adding" : "Removing", d
->c
);
1517 for (reg
= DNSServiceRegistrationList
; reg
; reg
= reg
->next
)
1519 if (reg
->DefaultDomain
)
1523 AddServiceInstance(reg
, d
);
1527 ServiceInstance
*si
= reg
->regs
, *prev
= NULL
;
1530 if (SameDomainName(&si
->domain
, d
))
1532 if (prev
) prev
->next
= si
->next
;
1533 else reg
->regs
= si
->next
;
1534 if (mDNS_DeregisterService(&mDNSStorage
, &si
->srs
))
1535 FreeServiceInstance(si
); // only free memory synchronously on error
1541 if (!si
) LogMsg("Requested removal of default domain %##s not in client %5d's list", d
, reg
->ClientMachPort
);
1547 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1548 DNSCString name
, DNSCString regtype
, DNSCString domain
, IPPort IpPort
, DNSCString txtRecord
)
1550 (void)unusedserver
; // Unused
1551 mStatus err
= mStatus_NoError
;
1552 const char *errormsg
= "Unknown";
1554 // older versions of this code passed the port via mach IPC as an int.
1555 // we continue to pass it as 4 bytes to maintain binary compatibility,
1556 // but now ensure that the network byte order is preserved by using a struct
1558 port
.b
[0] = IpPort
.bytes
[2];
1559 port
.b
[1] = IpPort
.bytes
[3];
1561 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1562 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1564 // Check for sub-types after the service type
1565 size_t reglen
= strlen(regtype
) + 1;
1566 if (reglen
> MAX_ESCAPED_DOMAIN_NAME
) { errormsg
= "reglen too long"; goto badparam
; }
1567 mDNSs32 NumSubTypes
= ChopSubTypes(regtype
); // Note: Modifies regtype string to remove trailing subtypes
1568 if (NumSubTypes
< 0) { errormsg
= "Bad Service SubType"; goto badparam
; }
1570 // Check other parameters
1574 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1575 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1576 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1577 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
1578 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1580 unsigned char txtinfo
[1024] = "";
1581 unsigned int data_len
= 0;
1582 unsigned int size
= sizeof(RDataBody
);
1583 unsigned char *pstring
= &txtinfo
[data_len
];
1584 char *ptr
= txtRecord
;
1586 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1587 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1588 // Hence we have to convert the C-string to a P-string.
1589 // ASCII-1 characters are allowed in the C-string as boundary markers,
1590 // so that a single C-string can be used to represent one or more P-strings.
1593 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1594 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1596 pstring
= &txtinfo
[data_len
];
1602 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1603 pstring
[++pstring
[0]] = *ptr
++;
1608 if (size
< data_len
)
1611 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1612 // a port number of zero. When two instances of the protected client are allowed to run on one
1613 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1614 if (port
.NotAnInteger
)
1616 int count
= CountExistingRegistrations(&srv
, port
);
1618 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1619 client
, count
+1, srv
.c
, mDNSVal16(port
));
1622 // Allocate memory, and handle failure
1623 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
));
1624 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1625 bzero(x
, sizeof(*x
));
1627 // Set up object, and link into list
1628 x
->ClientMachPort
= client
;
1629 x
->DefaultDomain
= !domain
[0];
1630 x
->autoname
= (!name
[0]);
1632 x
->NumSubTypes
= NumSubTypes
;
1633 memcpy(x
->regtype
, regtype
, reglen
);
1637 memcpy(x
->txtinfo
, txtinfo
, 1024);
1638 x
->txt_len
= data_len
;
1642 x
->next
= DNSServiceRegistrationList
;
1643 DNSServiceRegistrationList
= x
;
1645 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1646 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1648 err
= AddServiceInstance(x
, &d
);
1649 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; } // bail if .local (or explicit domain) fails
1651 if (x
->DefaultDomain
)
1653 DNameListElem
*ptr
, *regdomains
= mDNSPlatformGetRegDomainList();
1654 for (ptr
= regdomains
; ptr
; ptr
= ptr
->next
)
1655 AddServiceInstance(x
, &ptr
->name
);
1656 mDNS_FreeDNameList(regdomains
);
1659 // Succeeded: Wrap up and return
1660 EnableDeathNotificationForClient(client
, x
);
1661 return(mStatus_NoError
);
1664 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1666 err
= mStatus_BadParamErr
;
1668 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1669 client
, name
, regtype
, domain
, mDNSVal16(port
), errormsg
, err
);
1673 // This updates either the text of the field currently labelled "Local Hostname",
1674 // or the text of the field currently labelled "Computer Name"
1675 // in the Sharing Prefs Control Panel
1676 mDNSlocal
void RecordUpdatedName(const mDNS
*const m
, domainlabel
*n1
, domainlabel
*n2
, char *msg
, char *suffix
, CFStringRef subtext
)
1678 char oldname
[MAX_DOMAIN_LABEL
+1];
1679 char newname
[MAX_DOMAIN_LABEL
+1];
1680 ConvertDomainLabelToCString_unescaped(n1
, oldname
);
1681 ConvertDomainLabelToCString_unescaped(n2
, newname
);
1682 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
1683 const CFStringRef cfnewname
= CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
);
1684 const CFStringRef f1
= CFStringCreateWithCString(NULL
, "“%@%s”", kCFStringEncodingUTF8
);
1685 const CFStringRef f2
= CFStringCreateWithCString(NULL
, "“%@%s”", kCFStringEncodingUTF8
);
1686 const SCPreferencesRef session
= SCPreferencesCreate(NULL
, CFSTR("mDNSResponder"), NULL
);
1688 if (!cfoldname
|| !cfnewname
|| !f1
|| !f2
|| !session
|| !SCPreferencesLock(session
, 0)) // If we can't get the lock don't wait
1689 LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
1692 const CFStringRef s0
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1693 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, f1
, cfoldname
, suffix
);
1694 const CFStringRef s2
= CFStringCreateWithFormat(NULL
, NULL
, f2
, cfnewname
, suffix
);
1695 // const CFMutableArrayRef alertMessage = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1696 const CFMutableStringRef alertMessage
= CFStringCreateMutable(NULL
, 0);
1698 if (n2
== &m
->hostlabel
) result
= SCPreferencesSetLocalHostName(session
, cfnewname
);
1699 else result
= SCPreferencesSetComputerName(session
, cfnewname
, kCFStringEncodingUTF8
);
1700 if (!result
|| !SCPreferencesCommitChanges(session
) || !SCPreferencesApplyChanges(session
) || !s0
|| !s1
|| !s2
|| !alertMessage
)
1701 LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
1702 else if (m
->p
->NotifyUser
)
1704 // CFArrayAppendValue(alertMessage, s0);
1705 CFStringAppend(alertMessage
, s0
);
1706 CFStringAppend(alertMessage
, s1
);
1707 CFStringAppend(alertMessage
, CFSTR(" is already in use on this network. The name has been changed to "));
1708 CFStringAppend(alertMessage
, s2
);
1709 CFStringAppend(alertMessage
, CFSTR(" automatically."));
1710 CFUserNotificationDisplayNotice(60.0, // Auto-dismiss after 60 seconds
1711 kCFUserNotificationCautionAlertLevel
,
1712 NULL
, NULL
, NULL
, // iconURL, soundURL, localizationURL
1713 (CFStringRef
)alertMessage
, subtext
, NULL
); // alertHeader, alertMessage, defaultButtonTitle
1715 if (s0
) CFRelease(s0
);
1716 if (s1
) CFRelease(s1
);
1717 if (s2
) CFRelease(s2
);
1718 if (alertMessage
) CFRelease(alertMessage
);
1719 SCPreferencesUnlock(session
);
1721 if (cfoldname
) CFRelease(cfoldname
);
1722 if (cfnewname
) CFRelease(cfnewname
);
1723 if (f1
) CFRelease(f1
);
1724 if (f2
) CFRelease(f2
);
1725 if (session
) CFRelease(session
);
1728 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1731 if (result
== mStatus_NoError
)
1733 // Allow three seconds in case we get a Computer Name update too -- don't want to alert the user twice
1734 RecordUpdatedNiceLabel(m
, mDNSPlatformOneSecond
*3);
1736 else if (result
== mStatus_ConfigChanged
)
1738 DNSServiceRegistration
*r
;
1739 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1742 ServiceInstance
*si
;
1743 for (si
= r
->regs
; si
; si
= si
->next
)
1745 if (!SameDomainLabel(si
->name
.c
, m
->nicelabel
.c
))
1747 debugf("NetworkChanged renaming %##s to %#s", si
->srs
.RR_SRV
.resrec
.name
->c
, m
->nicelabel
.c
);
1748 si
->autorename
= mDNStrue
;
1749 if (mDNS_DeregisterService(m
, &si
->srs
)) // If service deregistered already, we can re-register immediately
1750 RegCallback(m
, &si
->srs
, mStatus_MemFree
);
1754 udsserver_handle_configchange();
1756 else if (result
== mStatus_GrowCache
)
1758 // Allocate another chunk of cache storage
1759 CacheEntity
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheEntity
) * RR_CACHE_SIZE
);
1760 if (storage
) mDNS_GrowCache(m
, storage
, RR_CACHE_SIZE
);
1764 //*************************************************************************************************************
1765 // Add / Update / Remove records from existing Registration
1767 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1768 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1770 // Check client parameter
1772 mStatus err
= mStatus_NoError
;
1773 const char *errormsg
= "Unknown";
1774 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1775 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1776 ServiceInstance
*si
;
1778 (void)unusedserver
; // Unused
1779 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1780 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1782 // Check other parameters
1783 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1784 if (data_len
> sizeof(RDataBody
)) size
= data_len
;
1785 else size
= sizeof(RDataBody
);
1788 *reference
= (natural_t
)id
;
1789 for (si
= x
->regs
; si
; si
= si
->next
)
1791 // Allocate memory, and handle failure
1792 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1793 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1795 // Fill in type, length, and data of new record
1796 extra
->r
.resrec
.rrtype
= type
;
1797 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1798 extra
->r
.resrec
.rdlength
= data_len
;
1799 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1802 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1803 client
, si
->srs
.RR_SRV
.resrec
.name
->c
, type
, data_len
, extra
);
1804 err
= mDNS_AddRecordToService(&mDNSStorage
, &si
->srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1808 freeL("Extra Resource Record", extra
);
1809 errormsg
= "mDNS_AddRecordToService";
1813 extra
->ClientID
= id
;
1816 return mStatus_NoError
;
1819 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
1820 return mStatus_UnknownErr
;
1823 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1826 if (OldRData
!= &rr
->rdatastorage
)
1827 freeL("Old RData", OldRData
);
1830 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1832 // Check client parameter
1833 mStatus err
= mStatus_NoError
;
1834 const char *errormsg
= "Unknown";
1835 domainname
*name
= (domainname
*)"";
1837 name
= srs
->RR_SRV
.resrec
.name
;
1839 unsigned int size
= sizeof(RDataBody
);
1840 if (size
< data_len
)
1843 // Allocate memory, and handle failure
1844 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1845 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1847 // Fill in new length, and data
1848 newrdata
->MaxRDLength
= size
;
1849 memcpy(&newrdata
->u
, data
, data_len
);
1852 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1853 client
, srs
->RR_SRV
.resrec
.name
->c
, data_len
);
1855 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1858 errormsg
= "mDNS_Update";
1859 freeL("RData", newrdata
);
1862 return(mStatus_NoError
);
1865 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1869 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1870 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1872 // Check client parameter
1873 mStatus err
= mStatus_NoError
;
1874 const char *errormsg
= "Unknown";
1875 domainname
*name
= (domainname
*)"";
1876 ServiceInstance
*si
;
1878 (void)unusedserver
; // unused
1879 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1880 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1881 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1882 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1884 // Check other parameters
1885 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1887 for (si
= x
->regs
; si
; si
= si
->next
)
1889 AuthRecord
*r
= NULL
;
1891 // Find the record we're updating. NULL reference means update the primary TXT record
1892 if (!reference
) r
= &si
->srs
.RR_TXT
;
1895 ExtraResourceRecord
*ptr
;
1896 for (ptr
= si
->srs
.Extras
; ptr
; ptr
= ptr
->next
)
1898 if ((natural_t
)ptr
->ClientID
== reference
)
1899 { r
= &ptr
->r
; break; }
1901 if (!r
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1903 err
= UpdateRecord(&si
->srs
, client
, r
, data
, data_len
, ttl
);
1904 if (err
) goto fail
; //!!!KRS this will cause failures for non-local defaults!
1907 return mStatus_NoError
;
1910 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
1914 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
1916 domainname
*name
= srs
->RR_SRV
.resrec
.name
;
1917 mStatus err
= mStatus_NoError
;
1920 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
->c
);
1922 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
, FreeExtraRR
, extra
);
1923 if (err
) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client
, name
->c
, err
);
1928 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1929 natural_t reference
)
1931 // Check client parameter
1932 (void)unusedserver
; // Unused
1933 mStatus err
= mStatus_NoError
;
1934 const char *errormsg
= "Unknown";
1935 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1936 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1937 ServiceInstance
*si
;
1939 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1940 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1942 for (si
= x
->regs
; si
; si
= si
->next
)
1944 ExtraResourceRecord
*e
;
1945 for (e
= si
->srs
.Extras
; e
; e
= e
->next
)
1947 if ((natural_t
)e
->ClientID
== reference
)
1949 err
= RemoveRecord(&si
->srs
, e
, client
);
1953 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
1956 return mStatus_NoError
;
1959 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
1963 //*************************************************************************************************************
1966 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1968 mig_reply_error_t
*request
= msg
;
1969 mig_reply_error_t
*reply
;
1970 mach_msg_return_t mr
;
1972 (void)port
; // Unused
1973 (void)size
; // Unused
1974 (void)info
; // Unused
1976 /* allocate a reply buffer */
1977 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
1979 /* call the MiG server routine */
1980 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
1982 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
1984 if (reply
->RetCode
== MIG_NO_REPLY
)
1987 * This return code is a little tricky -- it appears that the
1988 * demux routine found an error of some sort, but since that
1989 * error would not normally get returned either to the local
1990 * user or the remote one, we pretend it's ok.
1992 CFAllocatorDeallocate(NULL
, reply
);
1997 * destroy any out-of-line data in the request buffer but don't destroy
1998 * the reply port right (since we need that to send an error message).
2000 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
2001 mach_msg_destroy(&request
->Head
);
2004 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
2006 /* no reply port, so destroy the reply */
2007 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
2008 mach_msg_destroy(&reply
->Head
);
2009 CFAllocatorDeallocate(NULL
, reply
);
2016 * We don't want to block indefinitely because the client
2017 * isn't receiving messages from the reply port.
2018 * If we have a send-once right for the reply port, then
2019 * this isn't a concern because the send won't block.
2020 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
2021 * To avoid falling off the kernel's fast RPC path unnecessarily,
2022 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
2025 options
= MACH_SEND_MSG
;
2026 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
2027 options
|= MACH_SEND_TIMEOUT
;
2029 mr
= mach_msg(&reply
->Head
, /* msg */
2030 options
, /* option */
2031 reply
->Head
.msgh_size
, /* send_size */
2033 MACH_PORT_NULL
, /* rcv_name */
2034 MACH_MSG_TIMEOUT_NONE
, /* timeout */
2035 MACH_PORT_NULL
); /* notify */
2037 /* Has a message error occurred? */
2040 case MACH_SEND_INVALID_DEST
:
2041 case MACH_SEND_TIMED_OUT
:
2042 /* the reply can't be delivered, so destroy it */
2043 mach_msg_destroy(&reply
->Head
);
2047 /* Includes success case. */
2051 CFAllocatorDeallocate(NULL
, reply
);
2054 mDNSlocal kern_return_t
registerBootstrapService()
2056 kern_return_t status
;
2057 mach_port_t service_send_port
, service_rcv_port
;
2059 debugf("Registering Bootstrap Service");
2062 * See if our service name is already registered and if we have privilege to check in.
2064 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2065 if (status
== KERN_SUCCESS
)
2068 * If so, we must be a followup instance of an already defined server. In that case,
2069 * the bootstrap port we inherited from our parent is the server's privilege port, so set
2070 * that in case we have to unregister later (which requires the privilege port).
2072 server_priv_port
= bootstrap_port
;
2073 restarting_via_mach_init
= TRUE
;
2075 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
2077 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
2078 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
2079 if (status
!= KERN_SUCCESS
) return status
;
2081 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
2082 if (status
!= KERN_SUCCESS
)
2084 mach_port_deallocate(mach_task_self(), server_priv_port
);
2088 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
2089 if (status
!= KERN_SUCCESS
)
2091 mach_port_deallocate(mach_task_self(), server_priv_port
);
2092 mach_port_deallocate(mach_task_self(), service_send_port
);
2095 assert(service_send_port
== service_rcv_port
);
2099 * We have no intention of responding to requests on the service port. We are not otherwise
2100 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
2101 * So, we can dispose of all the rights we have for the service port. We don't destroy the
2102 * send right for the server's privileged bootstrap port - in case we have to unregister later.
2104 mach_port_destroy(mach_task_self(), service_rcv_port
);
2108 mDNSlocal kern_return_t
destroyBootstrapService()
2110 debugf("Destroying Bootstrap Service");
2111 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
2114 mDNSlocal
void ExitCallback(int signal
)
2116 LogMsgIdent(mDNSResponderVersionString
, "stopping");
2118 debugf("ExitCallback");
2119 if (!mDNS_DebugMode
&& !started_via_launchdaemon
&& signal
!= SIGHUP
)
2120 destroyBootstrapService();
2122 debugf("ExitCallback: Aborting MIG clients");
2123 while (DNSServiceDomainEnumerationList
)
2124 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
2125 while (DNSServiceBrowserList
)
2126 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
2127 while (DNSServiceResolverList
)
2128 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
2129 while (DNSServiceRegistrationList
)
2130 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
2132 debugf("ExitCallback: mDNS_Close");
2133 mDNS_Close(&mDNSStorage
);
2134 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
2138 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
2139 mDNSlocal
void HandleSIG(int signal
)
2142 debugf("HandleSIG %d", signal
);
2143 mach_msg_header_t header
;
2144 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
2145 header
.msgh_remote_port
= signal_port
;
2146 header
.msgh_local_port
= MACH_PORT_NULL
;
2147 header
.msgh_size
= sizeof(header
);
2148 header
.msgh_id
= signal
;
2149 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
2151 LogMsg("HandleSIG %d: mach_msg_send failed", signal
);
2152 if (signal
== SIGHUP
|| signal
== SIGTERM
|| signal
== SIGINT
) exit(-1);
2156 mDNSlocal
void INFOCallback(void)
2158 mDNSs32 utc
= mDNSPlatformUTC();
2159 DNSServiceDomainEnumeration
*e
;
2160 DNSServiceBrowser
*b
;
2161 DNSServiceResolver
*l
;
2162 DNSServiceRegistration
*r
;
2163 NetworkInterfaceInfoOSX
*i
;
2165 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
2167 udsserver_info(&mDNSStorage
);
2169 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
2170 LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
2172 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
2174 DNSServiceBrowserQuestion
*qptr
;
2175 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
2176 LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
2178 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2179 LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
2181 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
2183 ServiceInstance
*si
;
2184 for (si
= r
->regs
; si
; si
= si
->next
)
2185 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
));
2188 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
2191 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
2192 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, utc
- i
->LastSeen
);
2194 LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
2195 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
, &i
->BSSID
,
2196 i
->ifinfo
.InterfaceActive
? "Active" : " ",
2197 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
2198 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
2199 i
->ifinfo
.InterfaceID
,
2200 i
->ifinfo
.Advertise
? "Adv" : " ",
2201 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
2205 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
2208 mDNSlocal
void SignalCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
2210 (void)port
; // Unused
2211 (void)size
; // Unused
2212 (void)info
; // Unused
2213 mach_msg_header_t
*m
= (mach_msg_header_t
*)msg
;
2218 case SIGTERM
: ExitCallback(m
->msgh_id
); break;
2219 case SIGINFO
: INFOCallback(); break;
2220 case SIGUSR1
: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
2221 mDNSMacOSXNetworkChanged(&mDNSStorage
); break;
2222 default: LogMsg("SignalCallback: Unknown signal %d", m
->msgh_id
); break;
2226 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
2229 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
2230 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
2231 CFMachPortRef i_port
= CFMachPortCreate(NULL
, SignalCallback
, NULL
, NULL
);
2232 mach_port_t m_port
= CFMachPortGetPort(s_port
);
2233 char *MachServerName
= mDNSMacOSXSystemBuildNumber(NULL
) < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
2234 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
2235 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
2236 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
2237 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
2242 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
2244 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
2248 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
2249 rrcachestorage
, RR_CACHE_SIZE
,
2250 mDNS_Init_AdvertiseLocalAddresses
,
2251 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
2253 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
2255 client_death_port
= CFMachPortGetPort(d_port
);
2256 signal_port
= CFMachPortGetPort(i_port
);
2258 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
2259 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
2260 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
2264 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
2268 mDNSlocal mDNSs32
mDNSDaemonIdle(mDNS
*const m
)
2270 mDNSs32 now
= mDNS_TimeNow(m
);
2272 // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
2274 // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
2275 // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
2276 // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
2277 // we then systematically lose our own looped-back packets.
2278 if (m
->p
->NetworkChanged
&& now
- m
->p
->NetworkChanged
>= 0) { m
->p
->NetworkChanged
= 0; mDNSMacOSXNetworkChanged(m
); }
2280 // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
2281 mDNSs32 nextevent
= mDNS_Execute(m
);
2283 if (m
->p
->NetworkChanged
)
2284 if (nextevent
- m
->p
->NetworkChanged
> 0)
2285 nextevent
= m
->p
->NetworkChanged
;
2287 // 3. Deliver any waiting browse messages to clients
2288 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
2292 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
2293 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
2294 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
2295 DNSServiceBrowser
*x
= b
;
2297 if (x
->results
) // Try to deliver the list of results
2301 DNSServiceBrowserResult
*const r
= x
->results
;
2303 domainname type
, domain
;
2304 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
2305 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
2306 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
2307 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
2308 ConvertDomainLabelToCString_unescaped(&name
, cname
);
2309 ConvertDomainNameToCString(&type
, ctype
);
2310 ConvertDomainNameToCString(&domain
, cdom
);
2311 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2312 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2313 // If we failed to send the mach message, try again in one second
2314 if (status
== MACH_SEND_TIMED_OUT
)
2316 if (nextevent
- now
> mDNSPlatformOneSecond
)
2317 nextevent
= now
+ mDNSPlatformOneSecond
;
2322 x
->lastsuccess
= now
;
2323 x
->results
= x
->results
->next
;
2324 freeL("DNSServiceBrowserResult", r
);
2327 // If this client hasn't read a single message in the last 60 seconds, abort it
2328 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2329 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2333 DNSServiceResolver
*l
;
2334 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2335 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2338 LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
2339 "This places considerable burden on the network.", l
->i
.name
.c
);
2342 if (m
->p
->NotifyUser
)
2344 if (m
->p
->NotifyUser
- now
< 0)
2346 if (!SameDomainLabel(m
->p
->usernicelabel
.c
, m
->nicelabel
.c
))
2348 LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2349 RecordUpdatedName(m
, &m
->p
->usernicelabel
, &m
->nicelabel
, "The name of your computer ", "",
2350 CFSTR("To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field."));
2351 m
->p
->NotifyUser
= 0; // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
2353 if (!SameDomainLabel(m
->p
->userhostlabel
.c
, m
->hostlabel
.c
))
2355 LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2356 RecordUpdatedName(m
, &m
->p
->userhostlabel
, &m
->hostlabel
, "This computer's local hostname ", ".local",
2357 CFSTR("To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field."));
2359 m
->p
->NotifyUser
= 0;
2362 if (nextevent
- m
->p
->NotifyUser
> 0)
2363 nextevent
= m
->p
->NotifyUser
;
2369 mDNSlocal
void ShowTaskSchedulingError(mDNS
*const m
)
2373 LogMsg("Task Scheduling Error: Continuously busy for more than a second");
2375 if (m
->NewQuestions
&& (!m
->NewQuestions
->DelayAnswering
|| m
->timenow
- m
->NewQuestions
->DelayAnswering
>= 0))
2376 LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
2377 m
->NewQuestions
->qname
.c
, DNSTypeName(m
->NewQuestions
->qtype
));
2378 if (m
->NewLocalOnlyQuestions
)
2379 LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
2380 m
->NewLocalOnlyQuestions
->qname
.c
, DNSTypeName(m
->NewLocalOnlyQuestions
->qtype
));
2381 if (m
->NewLocalRecords
&& LocalRecordReady(m
->NewLocalRecords
))
2382 LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m
, m
->NewLocalRecords
));
2383 if (m
->SuppressSending
&& m
->timenow
- m
->SuppressSending
>= 0)
2384 LogMsg("Task Scheduling Error: m->SuppressSending %d", m
->timenow
- m
->SuppressSending
);
2385 #ifndef UNICAST_DISABLED
2386 if (m
->timenow
- m
->uDNS_info
.nextevent
>= 0)
2387 LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m
->timenow
- m
->uDNS_info
.nextevent
);
2389 if (m
->timenow
- m
->NextCacheCheck
>= 0)
2390 LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m
->timenow
- m
->NextCacheCheck
);
2391 if (m
->timenow
- m
->NextScheduledQuery
>= 0)
2392 LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m
->timenow
- m
->NextScheduledQuery
);
2393 if (m
->timenow
- m
->NextScheduledProbe
>= 0)
2394 LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m
->timenow
- m
->NextScheduledProbe
);
2395 if (m
->timenow
- m
->NextScheduledResponse
>= 0)
2396 LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m
->timenow
- m
->NextScheduledResponse
);
2398 mDNS_Unlock(&mDNSStorage
);
2401 mDNSexport
int main(int argc
, char **argv
)
2404 kern_return_t status
;
2406 for (i
=1; i
<argc
; i
++)
2408 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2409 if (!strcmp(argv
[i
], "-launchdaemon")) started_via_launchdaemon
= mDNStrue
;
2412 signal(SIGHUP
, HandleSIG
); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
2413 signal(SIGINT
, HandleSIG
); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
2414 signal(SIGPIPE
, SIG_IGN
); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
2415 signal(SIGTERM
, HandleSIG
); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
2416 signal(SIGINFO
, HandleSIG
); // (Debugging) Write state snapshot to syslog
2417 signal(SIGUSR1
, HandleSIG
); // (Debugging) Simulate network change notification from System Configuration Framework
2419 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2420 if (!mDNS_DebugMode
&& !started_via_launchdaemon
)
2422 registerBootstrapService();
2423 if (!restarting_via_mach_init
) exit(0); // mach_init will restart us immediately as a daemon
2424 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2425 if (fd
< 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno
, strerror(errno
));
2428 // Avoid unnecessarily duplicating a file descriptor to itself
2429 if (fd
!= STDIN_FILENO
) if (dup2(fd
, STDIN_FILENO
) < 0) LogMsg("dup2(fd, STDIN_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2430 if (fd
!= STDOUT_FILENO
) if (dup2(fd
, STDOUT_FILENO
) < 0) LogMsg("dup2(fd, STDOUT_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2431 if (fd
!= STDERR_FILENO
) if (dup2(fd
, STDERR_FILENO
) < 0) LogMsg("dup2(fd, STDERR_FILENO) failed errno %d (%s)", errno
, strerror(errno
));
2432 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
) (void)close(fd
);
2436 // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
2437 // The sooner we do this, the faster the machine will boot.
2438 status
= udsserver_init();
2439 if (status
) { LogMsg("Daemon start: udsserver_init failed"); return(status
); }
2441 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2442 LogMsgIdent(mDNSResponderVersionString
, "starting");
2443 status
= mDNSDaemonInitialize();
2445 #if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
2446 // Now that we're finished with anything privileged, switch over to running as "nobody"
2447 const struct passwd
*pw
= getpwnam("nobody");
2451 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2456 LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32
)mDNSStorage
.timenow_last
, mDNSStorage
.timenow_last
);
2458 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2460 // This is the main work loop:
2461 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2462 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2463 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2464 // (4) On wakeup we first process *all* events
2465 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2466 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2468 // 1. Before going into a blocking wait call and letting our process to go sleep,
2469 // call mDNSDaemonIdle to allow any deferred work to be completed.
2470 mDNSs32 nextevent
= mDNSDaemonIdle(&mDNSStorage
);
2471 nextevent
= udsserver_idle(nextevent
);
2473 // 2. Work out how long we expect to sleep before the next scheduled task
2474 mDNSs32 ticks
= nextevent
- mDNS_TimeNow(&mDNSStorage
);
2475 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2481 if (++RepeatedBusy
>= mDNSPlatformOneSecond
) { ShowTaskSchedulingError(&mDNSStorage
); RepeatedBusy
= 0; }
2483 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2485 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2486 // (a) our next wakeup time, or (b) an event occurs.
2487 // The 'true' parameter makes it return after handling any event that occurs
2488 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2489 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2491 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2493 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2494 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2497 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2501 LogMsg("ERROR: CFRunLoopRun Exiting.");
2502 mDNS_Close(&mDNSStorage
);
2505 if (!mDNS_DebugMode
&& !started_via_launchdaemon
) destroyBootstrapService();
2507 LogMsgIdent(mDNSResponderVersionString
, "exiting");
2511 // uds_daemon.c support routines /////////////////////////////////////////////
2513 // We keep a list of client-supplied event sources in PosixEventSource records
2514 struct CFSocketEventSource
2516 udsEventCallback Callback
;
2519 struct CFSocketEventSource
*Next
;
2521 CFRunLoopSourceRef RLS
;
2523 typedef struct CFSocketEventSource CFSocketEventSource
;
2525 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2527 static void cf_callback(CFSocketRef s
, CFSocketCallBackType t
, CFDataRef dr
, const void *c
, void *i
)
2528 // Called by CFSocket when data appears on socket
2534 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2535 source
->Callback(source
->Context
);
2538 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2539 // Arrange things so that callback is called with context when data appears on fd
2541 CFSocketEventSource
*newSource
;
2542 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2544 if (gEventSources
.LinkOffset
== 0)
2545 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2547 if (fd
>= FD_SETSIZE
|| fd
< 0)
2548 return mStatus_UnsupportedErr
;
2549 if (callback
== NULL
)
2550 return mStatus_BadParamErr
;
2552 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2553 if (NULL
== newSource
)
2554 return mStatus_NoMemoryErr
;
2556 newSource
->Callback
= callback
;
2557 newSource
->Context
= context
;
2560 cfContext
.info
= newSource
;
2561 if ( NULL
!= (newSource
->cfs
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2562 cf_callback
, &cfContext
)) &&
2563 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->cfs
, 0)))
2565 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2566 AddToTail(&gEventSources
, newSource
);
2572 CFSocketInvalidate(newSource
->cfs
); // Note: Also closes the underlying socket
2573 CFRelease(newSource
->cfs
);
2575 return mStatus_NoMemoryErr
;
2578 return mStatus_NoError
;
2581 mStatus
udsSupportRemoveFDFromEventLoop(int fd
) // Note: This also CLOSES the file descriptor
2582 // Reverse what was done in udsSupportAddFDToEventLoop().
2584 CFSocketEventSource
*iSource
;
2586 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2588 if (fd
== iSource
->fd
)
2590 RemoveFromList(&gEventSources
, iSource
);
2591 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2592 CFRunLoopSourceInvalidate(iSource
->RLS
);
2593 CFRelease(iSource
->RLS
);
2594 CFSocketInvalidate(iSource
->cfs
); // Note: Also closes the underlying socket
2595 CFRelease(iSource
->cfs
);
2597 return mStatus_NoError
;
2600 return mStatus_NoSuchNameErr
;
2603 // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
2604 const char *__crashreporter_info__
= mDNSResponderVersionString
;
2605 asm(".desc ___crashreporter_info__, 0x10");
2607 // For convenience when using the "strings" command, this is the last thing in the file
2608 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";