2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
27 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
28 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
29 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
30 * therefore common sense dictates that if they are part of a compound statement then they
31 * should be indented to the same level as everything else in that compound statement.
32 * Indenting curly braces at the same level as the "if" implies that curly braces are
33 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
34 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
35 * understand why variable y is not of type "char*" just proves the point that poor code
36 * layout leads people to unfortunate misunderstandings about how the C language really works.)
38 Change History (most recent first):
41 Revision 1.175 2004/06/10 20:23:21 cheshire
42 Also list interfaces in SIGINFO output
44 Revision 1.174 2004/06/08 18:54:48 ksekar
45 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
47 Revision 1.173 2004/06/08 17:35:12 cheshire
48 <rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
50 Revision 1.172 2004/06/05 00:04:26 cheshire
51 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
53 Revision 1.171 2004/06/04 08:58:30 ksekar
54 <rdar://problem/3668624>: Keychain integration for secure dynamic update
56 Revision 1.170 2004/05/30 20:01:50 ksekar
57 <rdar://problem/3668635>: wide-area default registrations should be in
58 .local too - fixed service registration when clients pass an explicit
59 domain (broken by previous checkin)
61 Revision 1.169 2004/05/30 01:30:16 ksekar
62 <rdar://problem/3668635>: wide-area default registrations should be in
65 Revision 1.168 2004/05/18 23:51:26 cheshire
66 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
68 Revision 1.167 2004/05/14 16:39:47 ksekar
69 Browse for iChat locally for now.
71 Revision 1.166 2004/05/13 21:33:52 ksekar
72 Clean up non-local registration control via config file. Force iChat
73 registrations to be local for now.
75 Revision 1.165 2004/05/13 04:54:20 ksekar
76 Unified list copy/free code. Added symetric list for
78 Revision 1.164 2004/05/12 22:03:08 ksekar
79 Made GetSearchDomainList a true platform-layer call (declaration moved
80 from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
81 only on non-OSX platforms. Changed call to return a copy of the list
82 to avoid shared memory issues. Added a routine to free the list.
84 Revision 1.163 2004/05/12 02:03:25 ksekar
85 Non-local domains will only be browsed by default, and show up in
86 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
88 Revision 1.162 2004/04/14 23:09:29 ksekar
89 Support for TSIG signed dynamic updates.
91 Revision 1.161 2004/04/07 01:20:04 cheshire
92 Hash slot value should be unsigned
94 Revision 1.160 2004/04/06 19:51:24 cheshire
95 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
96 After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
98 Revision 1.159 2004/04/03 01:36:55 cheshire
99 <rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
100 If "nobody" user doesn't exist, log a message and continue as "root"
102 Revision 1.158 2004/04/02 21:39:05 cheshire
103 Fix errors in comments
105 Revision 1.157 2004/03/19 18:49:10 ksekar
106 Increased size check in freeL() to account for LargeCacheRecord
107 structs larger than 8k
109 Revision 1.156 2004/03/19 18:19:19 ksekar
110 Fixed daemon.c to compile with malloc debugging turned on.
112 Revision 1.155 2004/03/13 01:57:34 ksekar
113 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
115 Revision 1.154 2004/03/12 08:42:47 cheshire
116 <rdar://problem/3548256>: Should not allow empty string for resolve domain
118 Revision 1.153 2004/03/12 08:08:51 cheshire
121 Revision 1.152 2004/02/05 19:39:29 cheshire
122 Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
123 so that all platforms get this functionality
125 Revision 1.151 2004/02/03 22:35:34 cheshire
126 <rdar://problem/3548256>: Should not allow empty string for resolve domain
128 Revision 1.150 2004/01/28 21:14:23 cheshire
129 Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
131 Revision 1.149 2004/01/28 02:30:08 ksekar
132 Added default Search Domains to unicast browsing, controlled via
133 Networking sharing prefs pane. Stopped sending unicast messages on
134 every interface. Fixed unicast resolving via mach-port API.
136 Revision 1.148 2004/01/25 00:03:20 cheshire
137 Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
139 Revision 1.147 2004/01/19 19:51:46 cheshire
140 Fix compiler error (mixed declarations and code) on some versions of Linux
142 Revision 1.146 2003/12/08 21:00:46 rpantos
143 Changes to support mDNSResponder on Linux.
145 Revision 1.145 2003/12/05 22:08:07 cheshire
146 Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
148 Revision 1.144 2003/11/19 23:21:08 ksekar
149 <rdar://problem/3486646>: config change handler not called for dns-sd services
151 Revision 1.143 2003/11/14 21:18:32 cheshire
152 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
153 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
155 Revision 1.142 2003/11/08 22:18:29 cheshire
156 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
158 Revision 1.141 2003/11/07 02:30:57 cheshire
159 Also check per-slot cache use counts in SIGINFO state log
161 Revision 1.140 2003/10/21 19:58:26 cheshire
162 <rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
164 Revision 1.139 2003/10/21 00:10:18 rpantos
165 <rdar://problem/3409401>: mDNSResponder should not run as root
167 Revision 1.138 2003/10/07 20:16:58 cheshire
168 Shorten syslog message a bit
170 Revision 1.137 2003/09/23 02:12:43 cheshire
171 Also include port number in list of services registered via new UDS API
173 Revision 1.136 2003/09/23 02:07:25 cheshire
174 Include port number in DNSServiceRegistration START/STOP messages
176 Revision 1.135 2003/09/23 01:34:02 cheshire
177 In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
179 Revision 1.134 2003/08/21 20:01:37 cheshire
180 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
182 Revision 1.133 2003/08/20 23:39:31 cheshire
183 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
185 Revision 1.132 2003/08/20 01:44:56 cheshire
186 Fix errors in LogOperation() calls (only used for debugging)
188 Revision 1.131 2003/08/19 05:39:43 cheshire
189 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
191 Revision 1.130 2003/08/16 03:39:01 cheshire
192 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
194 Revision 1.129 2003/08/15 20:16:03 cheshire
195 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
196 We want to avoid touching the rdata pages, so we don't page them in.
197 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
198 Moved this from the RData to the ResourceRecord object.
199 2. To avoid unnecessarily touching the rdata just to compare it,
200 compute a hash of the rdata and store the hash in the ResourceRecord object.
202 Revision 1.128 2003/08/14 19:30:36 cheshire
203 <rdar://problem/3378473> Include list of cache records in SIGINFO output
205 Revision 1.127 2003/08/14 02:18:21 cheshire
206 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
208 Revision 1.126 2003/08/12 19:56:25 cheshire
211 Revision 1.125 2003/08/08 18:36:04 cheshire
212 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
214 Revision 1.124 2003/07/25 18:28:23 cheshire
215 Minor fix to error messages in syslog: Display string parameters with quotes
217 Revision 1.123 2003/07/23 17:45:28 cheshire
218 <rdar://problem/3339388> mDNSResponder leaks a bit
219 Don't allocate memory for the reply until after we've verified that the reply is valid
221 Revision 1.122 2003/07/23 00:00:04 cheshire
224 Revision 1.121 2003/07/20 03:38:51 ksekar
225 <rdar://problem/3320722> Completed support for Unix-domain socket based API.
227 Revision 1.120 2003/07/18 00:30:00 cheshire
228 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
230 Revision 1.119 2003/07/17 19:08:58 cheshire
231 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
233 Revision 1.118 2003/07/15 21:12:28 cheshire
234 Added extra debugging checks in validatelists() (not used in final shipping version)
236 Revision 1.117 2003/07/15 01:55:15 cheshire
237 <rdar://problem/3315777> Need to implement service registration with subtypes
239 Revision 1.116 2003/07/02 21:19:51 cheshire
240 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
242 Revision 1.115 2003/07/02 02:41:24 cheshire
243 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
245 Revision 1.114 2003/07/01 21:10:20 cheshire
246 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
248 Revision 1.113 2003/06/28 17:27:43 vlubet
249 <rdar://problem/3221246> Redirect standard input, standard output, and
250 standard error file descriptors to /dev/null just like any other
253 Revision 1.112 2003/06/25 23:42:19 ksekar
254 <rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
255 Reviewed by: Stuart Cheshire
256 Added files necessary to implement Unix domain sockets based enhanced
257 Rendezvous APIs, and integrated with existing Mach-port based daemon.
259 Revision 1.111 2003/06/11 01:02:43 cheshire
260 <rdar://problem/3287858> mDNSResponder binary compatibility
261 Make single binary that can run on both Jaguar and Panther.
263 Revision 1.110 2003/06/10 01:14:11 cheshire
264 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
266 Revision 1.109 2003/06/06 19:53:43 cheshire
267 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
268 (Global search-and-replace; no functional change to code execution.)
270 Revision 1.108 2003/06/06 14:08:06 cheshire
271 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
273 Revision 1.107 2003/05/29 05:44:55 cheshire
274 Minor fixes to log messages
276 Revision 1.106 2003/05/27 18:30:55 cheshire
277 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
278 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
280 Revision 1.105 2003/05/26 03:21:29 cheshire
281 Tidy up address structure naming:
282 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
283 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
284 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
286 Revision 1.104 2003/05/26 00:42:06 cheshire
287 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
289 Revision 1.103 2003/05/23 23:07:44 cheshire
290 <rdar://problem/3268199> Must not write to stderr when running as daemon
292 Revision 1.102 2003/05/22 01:32:31 cheshire
293 Fix typo in Log message format string
295 Revision 1.101 2003/05/22 00:26:55 cheshire
296 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
297 Modify error message to explain that this is technically legal, but may indicate a bug.
299 Revision 1.100 2003/05/21 21:02:24 ksekar
300 <rdar://problem/3247035>: Service should be prefixed
301 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
302 Mach message port to "com.apple.mDNSResponder.
304 Revision 1.99 2003/05/21 17:33:49 cheshire
305 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
307 Revision 1.98 2003/05/20 00:33:07 cheshire
308 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
309 SIGHUP now writes state summary to syslog
311 Revision 1.97 2003/05/08 00:19:08 cheshire
312 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
314 Revision 1.96 2003/05/07 22:10:46 cheshire
315 <rdar://problem/3250330> Add a few more error logging messages
317 Revision 1.95 2003/05/07 19:20:17 cheshire
318 <rdar://problem/3251391> Add version number to mDNSResponder builds
320 Revision 1.94 2003/05/07 00:28:18 cheshire
321 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
323 Revision 1.93 2003/05/06 00:00:49 cheshire
324 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
326 Revision 1.92 2003/04/04 20:38:57 cheshire
331 #include <mach/mach.h>
332 #include <mach/mach_error.h>
333 #include <servers/bootstrap.h>
334 #include <sys/types.h>
340 #include "DNSServiceDiscoveryRequestServer.h"
341 #include "DNSServiceDiscoveryReply.h"
343 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
344 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
346 #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
348 #include "GenLinkedList.h"
350 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
352 //*************************************************************************************************************
355 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
356 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
357 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
358 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
359 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
361 // convenience definition
362 #define _UNUSED __attribute__ ((unused))
364 //*************************************************************************************************************
367 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
368 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
369 mDNSexport mDNS mDNSStorage
;
370 static mDNS_PlatformSupport PlatformStorage
;
371 #define RR_CACHE_SIZE 64
372 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
374 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
375 static mach_port_t client_death_port
= MACH_PORT_NULL
;
376 static mach_port_t exit_m_port
= MACH_PORT_NULL
;
377 static mach_port_t info_m_port
= MACH_PORT_NULL
;
378 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
380 // mDNS Mach Message Timeout, in milliseconds.
381 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
382 // fails to service its mach message queue, but long enough to give a well-written
383 // client a chance to service its mach message queue without getting cut off.
384 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
385 // even extra-slow clients a fair chance before we cut them off.
386 #define MDNS_MM_TIMEOUT 250
388 static int restarting_via_mach_init
= 0;
390 //*************************************************************************************************************
391 // Active client list structures
393 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
394 struct DNSServiceDomainEnumeration_struct
396 DNSServiceDomainEnumeration
*next
;
397 mach_port_t ClientMachPort
;
398 DNSQuestion dom
; // Question asking for domains
399 DNSQuestion def
; // Question asking for default domain
402 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
403 struct DNSServiceBrowserResult_struct
405 DNSServiceBrowserResult
*next
;
410 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
412 typedef struct DNSServiceBrowserQuestion
414 struct DNSServiceBrowserQuestion
*next
;
416 } DNSServiceBrowserQuestion
;
418 struct DNSServiceBrowser_struct
420 DNSServiceBrowser
*next
;
421 mach_port_t ClientMachPort
;
422 DNSServiceBrowserQuestion
*qlist
;
423 DNSServiceBrowserResult
*results
;
427 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
428 struct DNSServiceResolver_struct
430 DNSServiceResolver
*next
;
431 mach_port_t ClientMachPort
;
438 typedef struct ExtraRecordRef
440 ExtraResourceRecord
*localRef
; // extra added to .local service
441 ExtraResourceRecord
*globalRef
; // extra added to default global service (may be NULL)
442 struct ExtraRecordRef
*next
;
445 typedef struct DNSServiceRegistration_struct DNSServiceRegistration
;
446 struct DNSServiceRegistration_struct
448 DNSServiceRegistration
*next
;
449 mach_port_t ClientMachPort
;
451 mDNSBool autorenameLS
;
452 mDNSBool autorenameGS
;
453 mDNSBool deallocate
; // gs and ls (below) will receive separate MemFree callbacks,
454 // the latter of which must deallocate the wrapper structure.
455 // ls MemFree callback: if (!gs) free wrapper; else set deallocate flag
456 // gs callback: if (deallocate) free wrapper; else free (gs), gs = NULL
458 ExtraRecordRef
*ExtraRefList
;
459 ServiceRecordSet
*gs
; // default "global" (wide area) service (may be NULL)
460 ServiceRecordSet ls
; // .local service (also used if client passes an explicit domain)
461 // Don't add any fields after ServiceRecordSet.
462 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
465 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
466 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
467 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
468 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
470 //*************************************************************************************************************
471 // General Utility Functions
473 #if MACOSX_MDNS_MALLOC_DEBUGGING
475 char _malloc_options
[] = "AXZ";
477 static void validatelists(mDNS
*const m
)
479 DNSServiceDomainEnumeration
*e
;
480 DNSServiceBrowser
*b
;
481 DNSServiceResolver
*l
;
482 DNSServiceRegistration
*r
;
488 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
489 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
490 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
);
492 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
493 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
494 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
);
496 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
497 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
498 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
);
500 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
501 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
502 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
);
504 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
505 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
506 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
508 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
509 if (rr
->resrec
.RecordType
== 0 || rr
->resrec
.RecordType
== 0xFF)
510 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->resrec
.RecordType
);
512 for (q
= m
->Questions
; q
; q
=q
->next
)
513 if (q
->ThisQInterval
== (mDNSs32
)~0)
514 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
);
516 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
517 for (cr
= mDNSStorage
.rrcache_hash
[slot
]; cr
; cr
=cr
->next
)
518 if (cr
->resrec
.RecordType
== 0 || cr
->resrec
.RecordType
== 0xFF)
519 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->resrec
.RecordType
);
522 void *mallocL(char *msg
, unsigned int size
)
524 unsigned long *mem
= malloc(size
+8);
527 LogMsg("malloc( %s : %d ) failed", msg
, size
);
532 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
535 //bzero(&mem[2], size);
536 memset(&mem
[2], 0xFF, size
);
537 validatelists(&mDNSStorage
);
542 void freeL(char *msg
, void *x
)
545 LogMsg("free( %s @ NULL )!", msg
);
548 unsigned long *mem
= ((unsigned long *)x
) - 2;
549 if (mem
[0] != 0xDEAD1234)
550 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
552 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
553 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
554 //bzero(mem, mem[1]+8);
555 memset(mem
, 0xFF, mem
[1]+8);
556 validatelists(&mDNSStorage
);
563 //*************************************************************************************************************
564 // Client Death Detection
566 mDNSlocal
void FreeSRS(ServiceRecordSet
*s
)
570 ExtraResourceRecord
*extras
= s
->Extras
;
571 s
->Extras
= s
->Extras
->next
;
572 if (extras
->r
.resrec
.rdata
!= &extras
->r
.rdatastorage
)
573 freeL("Extra RData", extras
->r
.resrec
.rdata
);
574 freeL("ExtraResourceRecord", extras
);
577 if (s
->RR_TXT
.resrec
.rdata
!= &s
->RR_TXT
.rdatastorage
)
578 freeL("TXT RData", s
->RR_TXT
.resrec
.rdata
);
580 if (s
->SubTypes
) freeL("ServiceSubTypes", s
->SubTypes
);
583 mDNSlocal
void FreeDNSServiceRegistration(ServiceRecordSet
*srs
)
585 DNSServiceRegistration
*x
= srs
->ServiceContext
;
586 ExtraRecordRef
*ref
, *fptr
;
591 freeL("DNSServiceRegistration GlobalService", srs
);
594 else x
->deallocate
= mDNStrue
;
596 if (x
->deallocate
&& !x
->gs
)
598 ref
= x
->ExtraRefList
;
600 { fptr
= ref
; ref
= ref
->next
; freeL("ExtraRecordRef", fptr
); }
601 freeL("DNSServiceRegistration", x
);
606 // AbortClient finds whatever client is identified by the given Mach port,
607 // stops whatever operation that client was doing, and frees its memory.
608 // In the case of a service registration, the actual freeing may be deferred
609 // until we get the mStatus_MemFree message, if necessary
610 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
612 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
613 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
614 DNSServiceResolver
**l
= &DNSServiceResolverList
;
615 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
617 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
620 DNSServiceDomainEnumeration
*x
= *e
;
623 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
624 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
625 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
626 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
627 freeL("DNSServiceDomainEnumeration", x
);
631 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
634 DNSServiceBrowser
*x
= *b
;
635 DNSServiceBrowserQuestion
*freePtr
, *qptr
= x
->qlist
;
640 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, qptr
->q
.qname
.c
, m
, x
);
641 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort
, qptr
->q
.qname
.c
);
642 mDNS_StopBrowse(&mDNSStorage
, &qptr
->q
);
645 freeL("DNSServiceBrowserQuestion", freePtr
);
649 DNSServiceBrowserResult
*r
= x
->results
;
650 x
->results
= x
->results
->next
;
651 freeL("DNSServiceBrowserResult", r
);
653 freeL("DNSServiceBrowser", x
);
657 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
660 DNSServiceResolver
*x
= *l
;
663 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
664 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
665 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
666 freeL("DNSServiceResolver", x
);
670 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
673 DNSServiceRegistration
*x
= *r
;
675 x
->autorenameLS
= mDNSfalse
;
676 x
->autorenameGS
= mDNSfalse
;
679 LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort
, x
->ls
.RR_SRV
.resrec
.name
.c
, SRS_PORT(&x
->ls
), m
, x
);
680 if (x
->gs
) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort
, x
->gs
->RR_SRV
.resrec
.name
.c
, SRS_PORT(x
->gs
), m
, x
);
684 LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, x
->ls
.RR_SRV
.resrec
.name
.c
, SRS_PORT(&x
->ls
));
685 if (x
->gs
) LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort
, x
->gs
->RR_SRV
.resrec
.name
.c
, SRS_PORT(x
->gs
));
687 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
688 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
689 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
690 // the list, so we should go ahead and free the memory right now
691 if (x
->gs
&& mDNS_DeregisterService(&mDNSStorage
, x
->gs
))
693 // Deregister returned an error, so we free immediately
697 if (mDNS_DeregisterService(&mDNSStorage
, &x
->ls
))
698 FreeDNSServiceRegistration(&x
->ls
);
702 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
705 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
707 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
709 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
710 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
711 DNSServiceResolver
*l
= DNSServiceResolverList
;
712 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
713 DNSServiceBrowserQuestion
*qptr
;
715 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
716 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
717 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
718 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
719 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
722 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
723 LogMsg("%5d: Browser(%##s) %s%s", c
, qptr
->q
.qname
.c
, reason
, msg
);
725 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
728 LogMsg("%5d: Registration(%##s) %s%s", c
, r
->ls
.RR_SRV
.resrec
.name
.c
, reason
, msg
);
729 if (r
->gs
) LogMsg("%5d: Registration(%##s) %s%s", c
, r
->gs
->RR_SRV
.resrec
.name
.c
, reason
, msg
);
731 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
736 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
738 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
739 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
740 DNSServiceResolver
*l
= DNSServiceResolverList
;
741 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
742 DNSServiceBrowserQuestion
*qptr
;
744 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
745 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
746 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
747 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
748 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
751 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
752 LogMsg("%5d: Browser(%##s) already exists!", c
, qptr
->q
.qname
.c
);
754 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
755 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->ls
.RR_SRV
.resrec
.name
.c
);
756 return(e
|| b
|| l
|| r
);
759 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
761 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
762 (void)unusedport
; // Unused
763 (void)size
; // Unused
764 (void)info
; // Unused
765 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
767 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
768 AbortClient(deathMessage
->not_port
, NULL
);
770 /* Deallocate the send right that came in the dead name notification */
771 mach_port_destroy(mach_task_self(), deathMessage
->not_port
);
775 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
778 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
779 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
780 // If the port already died while we were thinking about it, then abort the operation right away
781 if (r
!= KERN_SUCCESS
)
782 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
785 //*************************************************************************************************************
786 // Domain Enumeration
788 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
790 kern_return_t status
;
792 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
793 DNSServiceDomainEnumerationReplyResultType rt
;
794 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
796 debugf("FoundDomain: %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
797 if (answer
->rrtype
!= kDNSType_PTR
) return;
798 if (!x
) { debugf("FoundDomain: DNSServiceDomainEnumeration is NULL"); return; }
802 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
803 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
807 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
811 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
812 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
813 !AddRecord
? "RemoveDomain" :
814 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
816 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
817 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
818 if (status
== MACH_SEND_TIMED_OUT
)
819 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
822 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
825 // Check client parameter
826 (void)unusedserver
; // Unused
827 mStatus err
= mStatus_NoError
;
828 const char *errormsg
= "Unknown";
829 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
830 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
832 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
833 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
834 const DNSServiceDomainEnumerationReplyResultType rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
836 // Allocate memory, and handle failure
837 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
838 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
840 // Set up object, and link into list
841 x
->ClientMachPort
= client
;
842 x
->next
= DNSServiceDomainEnumerationList
;
843 DNSServiceDomainEnumerationList
= x
;
845 // Generate initial response
846 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
847 // We always give local. as the initial default browse domain, and then look for more
848 kern_return_t status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, "local.", 0, MDNS_MM_TIMEOUT
);
849 if (status
== MACH_SEND_TIMED_OUT
)
850 { AbortBlockedClient(x
->ClientMachPort
, "local enumeration", x
); return(mStatus_UnknownErr
); }
853 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, NULL
, mDNSInterface_LocalOnly
, FoundDomain
, x
);
854 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, NULL
, mDNSInterface_LocalOnly
, FoundDomain
, x
);
855 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
857 // Succeeded: Wrap up and return
858 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
859 EnableDeathNotificationForClient(client
, x
);
860 return(mStatus_NoError
);
863 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
867 //*************************************************************************************************************
868 // Browse for services
870 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
874 if (answer
->rrtype
!= kDNSType_PTR
)
875 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
878 domainname type
, domain
;
879 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
881 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
882 answer
->name
.c
, answer
->rdata
->u
.name
.c
);
886 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
887 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
889 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
890 AssignDomainName(x
->result
, answer
->rdata
->u
.name
);
892 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
893 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
896 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
897 DNSServiceBrowserResult
**p
= &browser
->results
;
898 while (*p
) p
= &(*p
)->next
;
902 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
903 DNSCString regtype
, DNSCString domain
)
905 // Check client parameter
906 (void)unusedserver
; // Unused
907 mStatus err
= mStatus_NoError
;
908 const char *errormsg
= "Unknown";
909 DNameListElem
*SearchDomains
= NULL
, *sdPtr
;
910 DNSServiceBrowserQuestion
*qptr
;
912 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
913 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
915 // Check other parameters
917 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
919 // Allocate memory, and handle failure
920 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
921 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
923 // Set up object, and link into list
924 x
->ClientMachPort
= client
;
928 x
->next
= DNSServiceBrowserList
;
929 DNSServiceBrowserList
= x
;
931 //!!!KRS browse locally for ichat
932 if (!domain
[0] && (!strcmp(regtype
, "_ichat._tcp.") || !strcmp(regtype
, "_presence._tcp.")))
937 // Start browser for an explicit domain
938 x
->qlist
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
939 x
->qlist
->next
= NULL
;
940 if (!x
->qlist
) { err
= mStatus_UnknownErr
; AbortClient(client
, x
); errormsg
= "malloc"; goto fail
; }
942 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Illegal domain"; goto badparam
; }
943 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client
, t
.c
, d
.c
);
944 err
= mDNS_StartBrowse(&mDNSStorage
, &x
->qlist
->q
, &t
, &d
, mDNSInterface_Any
, FoundInstance
, x
);
945 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartBrowse"; goto fail
; }
949 // Start browser on all domains
950 SearchDomains
= mDNSPlatformGetSearchDomainList();
951 if (!SearchDomains
) { AbortClient(client
, x
); errormsg
= "GetSearchDomainList"; goto fail
; }
952 for (sdPtr
= SearchDomains
; sdPtr
; sdPtr
= sdPtr
->next
)
954 qptr
= mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion
));
955 if (!qptr
) { err
= mStatus_UnknownErr
; AbortClient(client
, x
); errormsg
= "malloc"; goto fail
; }
956 qptr
->next
= x
->qlist
;
958 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client
, t
.c
, sdPtr
->name
.c
);
959 err
= mDNS_StartBrowse(&mDNSStorage
, &qptr
->q
, &t
, &sdPtr
->name
, mDNSInterface_Any
, FoundInstance
, x
);
960 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartBrowse"; goto fail
; }
963 // Succeeded: Wrap up and return
964 EnableDeathNotificationForClient(client
, x
);
965 mDNS_FreeDNameList(SearchDomains
);
966 return(mStatus_NoError
);
969 err
= mStatus_BadParamErr
;
971 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
972 if (SearchDomains
) mDNS_FreeDNameList(SearchDomains
);
976 //*************************************************************************************************************
977 // Resolve Service Info
979 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
981 kern_return_t status
;
982 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
983 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
984 if (query
->info
->InterfaceID
== (mDNSInterfaceID
)~0) ifx
= mDNSNULL
;
985 struct sockaddr_storage interface
;
986 struct sockaddr_storage address
;
988 int i
, pstrlen
= query
->info
->TXTinfo
[0];
991 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
993 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
995 bzero(&interface
, sizeof(interface
));
996 bzero(&address
, sizeof(address
));
998 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
1000 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
1001 sin
->sin_len
= sizeof(*sin
);
1002 sin
->sin_family
= AF_INET
;
1004 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
1006 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
1008 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
1009 sin6
->sin6_len
= sizeof(*sin6
);
1010 sin6
->sin6_family
= AF_INET6
;
1011 sin6
->sin6_flowinfo
= 0;
1012 sin6
->sin6_port
= 0;
1013 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
1014 sin6
->sin6_scope_id
= ifx
->scope_id
;
1017 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
1019 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
1020 sin
->sin_len
= sizeof(*sin
);
1021 sin
->sin_family
= AF_INET
;
1022 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
1023 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
1027 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
1028 sin6
->sin6_len
= sizeof(*sin6
);
1029 sin6
->sin6_family
= AF_INET6
;
1030 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
1031 sin6
->sin6_flowinfo
= 0;
1032 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
1033 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
1036 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
1037 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
1038 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
1039 // ASCII-1 characters are used in the C-string as boundary markers,
1040 // to indicate the boundaries between the original constituent P-strings.
1041 for (i
=1; i
<query
->info
->TXTlen
; i
++)
1044 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
1048 pstrlen
= query
->info
->TXTinfo
[i
];
1051 cstring
[i
-1] = 0; // Put the terminating NULL on the end
1053 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x
->ClientMachPort
,
1054 x
->i
.name
.c
, &query
->info
->ip
, mDNSVal16(query
->info
->port
));
1055 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
1056 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
1057 if (status
== MACH_SEND_TIMED_OUT
)
1058 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
1061 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
1062 DNSCString name
, DNSCString regtype
, DNSCString domain
)
1064 // Check client parameter
1065 (void)unusedserver
; // Unused
1066 mStatus err
= mStatus_NoError
;
1067 const char *errormsg
= "Unknown";
1068 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1069 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1071 // Check other parameters
1073 domainname t
, d
, srv
;
1074 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1075 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1076 if (!domain
[0] || !MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1077 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1079 // Allocate memory, and handle failure
1080 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
1081 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1083 // Set up object, and link into list
1084 x
->ClientMachPort
= client
;
1085 x
->i
.InterfaceID
= mDNSInterface_Any
;
1087 x
->ReportTime
= (mDNSPlatformTimeNow() + 130 * mDNSPlatformOneSecond
) | 1;
1088 // Don't report errors for old iChat ("_ichat._tcp") service.
1089 // New iChat ("_presence._tcp") uses DNSServiceQueryRecord() (from /usr/include/dns_sd.h) instead,
1090 // and so should other applications that have valid reasons to be doing ongoing record monitoring.
1091 if (SameDomainLabel(t
.c
, (mDNSu8
*)"\x6_ichat")) x
->ReportTime
= 0;
1092 x
->next
= DNSServiceResolverList
;
1093 DNSServiceResolverList
= x
;
1096 LogOperation("%5d: DNSServiceResolver(%##s) START", client
, x
->i
.name
.c
);
1097 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
1098 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
1100 // Succeeded: Wrap up and return
1101 EnableDeathNotificationForClient(client
, x
);
1102 return(mStatus_NoError
);
1105 err
= mStatus_BadParamErr
;
1107 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
1111 //*************************************************************************************************************
1114 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
1116 DNSServiceRegistration
*x
= (DNSServiceRegistration
*)sr
->ServiceContext
;
1118 if (result
== mStatus_NoError
)
1120 kern_return_t status
;
1121 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
, SRS_PORT(sr
));
1122 status
= DNSServiceRegistrationReply_rpc(x
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1123 if (status
== MACH_SEND_TIMED_OUT
)
1124 AbortBlockedClient(x
->ClientMachPort
, "registration success", x
);
1127 else if (result
== mStatus_NameConflict
)
1129 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
, SRS_PORT(sr
));
1130 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
1131 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
1133 mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
1136 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
1137 // of their registration in the usual way (which we will catch via client death notification).
1138 // If the Mach queue is full, we forcibly abort the client immediately.
1139 kern_return_t status
= DNSServiceRegistrationReply_rpc(x
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
1140 if (status
== MACH_SEND_TIMED_OUT
)
1141 AbortBlockedClient(x
->ClientMachPort
, "registration conflict", x
);
1145 else if (result
== mStatus_MemFree
)
1147 mDNSBool
*autorename
= (sr
== &x
->ls
? &x
->autorenameLS
: &x
->autorenameGS
);
1150 debugf("RegCallback renaming %#s to %#s", x
->name
.c
, mDNSStorage
.nicelabel
.c
);
1151 *autorename
= mDNSfalse
;
1152 x
->name
= mDNSStorage
.nicelabel
;
1153 mDNS_RenameAndReregisterService(m
, sr
, &x
->name
);
1157 // SANITY CHECK: Should only get mStatus_MemFree as a result of calling mDNS_DeregisterService()
1158 // and should only get it with x->autorename false if we've already removed the record from our
1159 // list, but this check is just to make sure...
1160 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
1161 while (*r
&& *r
!= x
) r
= &(*r
)->next
;
1164 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr
->RR_SRV
.resrec
.name
.c
);
1168 LogOperation("%5d: DNSServiceRegistration(%##s, %u) Memory Free", x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
, SRS_PORT(sr
));
1169 FreeDNSServiceRegistration(sr
);
1175 LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld",
1176 x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
, SRS_PORT(sr
), result
);
1177 if (sr
== x
->gs
) { freeL("RegCallback - ServiceRecordSet", x
->gs
); x
->gs
= NULL
; }
1181 mDNSlocal
void CheckForDuplicateRegistrations(DNSServiceRegistration
*x
, domainname
*srv
, mDNSIPPort port
)
1183 int count
= 1; // Start with the one we're planning to register, then see if there are any more
1185 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
1186 if (rr
->resrec
.rrtype
== kDNSType_SRV
&&
1187 rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
== port
.NotAnInteger
&&
1188 SameDomainName(&rr
->resrec
.name
, srv
))
1192 LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
1193 x
->ClientMachPort
, count
, srv
->c
, mDNSVal16(port
));
1196 // Pass NULL for x to allocate the structure (for local service). Call again w/ initialized x to add a global service.
1197 mDNSlocal DNSServiceRegistration
*RegisterService(mach_port_t client
, DNSCString name
, DNSCString regtype
, DNSCString domain
,
1198 int notAnIntPort
, DNSCString txtRecord
, DNSServiceRegistration
*x
)
1200 ServiceRecordSet
*srs
= NULL
; // record set to use in registration operation
1201 mStatus err
= mStatus_NoError
;
1202 const char *errormsg
= "Unknown";
1204 // Check for sub-types after the service type
1205 AuthRecord
*SubTypes
= mDNSNULL
;
1206 mDNSu32 i
, NumSubTypes
= 0;
1207 char *comma
= regtype
;
1208 while (*comma
&& *comma
!= ',') comma
++;
1209 if (*comma
) // If we found a comma...
1211 *comma
= 0; // Overwrite the first comma with a nul
1212 char *p
= comma
+ 1; // Start scanning from the next character
1215 if ( !(*p
&& *p
!= ',')) { errormsg
= "Bad Service SubType"; goto badparam
; }
1216 while (*p
&& *p
!= ',') p
++;
1222 // Check other parameters
1226 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
1227 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
1228 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
1230 if (!MakeDomainNameFromDNSNameString(&d
, domain
)) { errormsg
= "Bad Domain"; goto badparam
; }
1231 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
1234 port
.NotAnInteger
= notAnIntPort
;
1236 unsigned char txtinfo
[1024] = "";
1237 unsigned int data_len
= 0;
1238 unsigned int size
= sizeof(RDataBody
);
1239 unsigned char *pstring
= &txtinfo
[data_len
];
1240 char *ptr
= txtRecord
;
1242 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
1243 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
1244 // Hence we have to convert the C-string to a P-string.
1245 // ASCII-1 characters are allowed in the C-string as boundary markers,
1246 // so that a single C-string can be used to represent one or more P-strings.
1249 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1250 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1252 pstring
= &txtinfo
[data_len
];
1258 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1259 pstring
[++pstring
[0]] = *ptr
++;
1264 if (size
< data_len
)
1267 // Allocate memory, and handle failure
1270 x
= mallocL("DNSServiceRegistration", sizeof(*x
) - sizeof(RDataBody
) + size
);
1271 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1272 bzero(x
, sizeof(*x
) - sizeof(RDataBody
) + size
);
1273 // Set up object, and link into list
1274 x
->ClientMachPort
= client
;
1275 x
->autoname
= (!name
[0]);
1277 x
->next
= DNSServiceRegistrationList
;
1278 DNSServiceRegistrationList
= x
;
1283 x
->gs
= mallocL("DNSServiceRegistration GlobalService", sizeof(ServiceRecordSet
) - sizeof(RDataBody
) + size
);
1284 if (!x
->gs
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1286 bzero(srs
, sizeof(ServiceRecordSet
) - sizeof(RDataBody
) + size
);
1291 SubTypes
= mallocL("ServiceSubTypes", NumSubTypes
* sizeof(AuthRecord
));
1292 if (!SubTypes
) { freeL("DNSServiceRegistration", x
); err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1293 for (i
= 0; i
< NumSubTypes
; i
++)
1295 comma
++; // Advance over the nul character
1296 MakeDomainNameFromDNSNameString(&SubTypes
[i
].resrec
.name
, comma
);
1297 while (*comma
) comma
++; // Advance comma to point to the next terminating nul
1302 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
1303 x
->ClientMachPort
, name
, regtype
, domain
, mDNSVal16(port
));
1304 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1305 // a port number of zero. When two instances of the protected client are allowed to run on one
1306 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1307 if (port
.NotAnInteger
) CheckForDuplicateRegistrations(x
, &srv
, port
);
1309 err
= mDNS_RegisterService(&mDNSStorage
, srs
,
1310 &x
->name
, &t
, &d
, // Name, type, domain
1311 mDNSNULL
, port
, // Host and port
1312 txtinfo
, data_len
, // TXT data, length
1313 SubTypes
, NumSubTypes
, // Subtypes
1314 mDNSInterface_Any
, // Interface ID
1315 RegCallback
, x
); // Callback and context
1319 if (srs
== &x
->ls
) AbortClient(client
, x
); // don't abort client for global service
1320 else FreeDNSServiceRegistration(x
->gs
);
1321 errormsg
= "mDNS_RegisterService";
1327 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1329 err
= mStatus_BadParamErr
;
1331 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1332 client
, name
, regtype
, domain
, notAnIntPort
, errormsg
, err
);
1336 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
1337 DNSCString name
, DNSCString regtype
, DNSCString domain
, int notAnIntPort
, DNSCString txtRecord
)
1339 // Check client parameter
1340 (void)unusedserver
; // Unused
1341 mStatus err
= mStatus_NoError
;
1342 const char *errormsg
= "Unknown";
1343 DNSServiceRegistration
*x
= NULL
;
1344 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1345 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
1347 x
= RegisterService(client
, name
, regtype
, *domain
? domain
: "local.", notAnIntPort
, txtRecord
, NULL
);
1348 if (!x
) { err
= mStatus_UnknownErr
; goto fail
; }
1350 //!!!KRS if we got a dynamic reg domain from the config file, use it for default (except for iChat)
1351 if (!*domain
&& mDNSStorage
.uDNS_info
.ServiceRegDomain
[0] && strcmp(regtype
, "_presence._tcp.") && strcmp(regtype
, "_ichat._tcp."))
1352 x
= RegisterService(client
, name
, regtype
, mDNSStorage
.uDNS_info
.ServiceRegDomain
, notAnIntPort
, txtRecord
, x
);
1354 // Succeeded: Wrap up and return
1355 EnableDeathNotificationForClient(client
, x
);
1356 return(mStatus_NoError
);
1359 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1360 client
, name
, regtype
, domain
, notAnIntPort
, errormsg
, err
);
1361 return mStatus_UnknownErr
;
1364 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1367 if (result
== mStatus_ConfigChanged
)
1369 DNSServiceRegistration
*r
;
1370 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1371 if (r
->autoname
&& !SameDomainLabel(r
->name
.c
, mDNSStorage
.nicelabel
.c
))
1373 debugf("NetworkChanged renaming %#s to %#s", r
->name
.c
, mDNSStorage
.nicelabel
.c
);
1374 r
->autorenameLS
= mDNStrue
;
1375 mDNS_DeregisterService(&mDNSStorage
, &r
->ls
);
1376 if (r
->gs
) { mDNS_DeregisterService(&mDNSStorage
, r
->gs
); r
->autorenameGS
= mDNStrue
; }
1378 udsserver_handle_configchange();
1380 else if (result
== mStatus_GrowCache
)
1382 // If we've run out of cache space, then double the total cache size and give the memory to mDNSCore
1383 mDNSu32 numrecords
= m
->rrcache_size
;
1384 CacheRecord
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheRecord
) * numrecords
);
1385 if (storage
) mDNS_GrowCache(&mDNSStorage
, storage
, numrecords
);
1389 //*************************************************************************************************************
1390 // Add / Update / Remove records from existing Registration
1393 mDNSlocal ExtraResourceRecord
*AddExtraRecord(DNSServiceRegistration
*x
, ServiceRecordSet
*srs
, mach_port_t client
,
1394 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1396 mStatus err
= mStatus_NoError
;
1397 const char *errormsg
= "Unknown";
1398 domainname
*name
= (domainname
*)"";
1399 name
= &srs
->RR_SRV
.resrec
.name
;
1403 unsigned int size
= sizeof(RDataBody
);
1404 if (size
< data_len
)
1407 // Allocate memory, and handle failure
1408 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1409 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1411 // Fill in type, length, and data of new record
1412 extra
->r
.resrec
.rrtype
= type
;
1413 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1414 extra
->r
.resrec
.rdlength
= data_len
;
1415 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1418 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1419 client
, srs
->RR_SRV
.resrec
.name
.c
, type
, data_len
, extra
);
1420 err
= mDNS_AddRecordToService(&mDNSStorage
, srs
, extra
, &extra
->r
.rdatastorage
, ttl
);
1424 freeL("Extra Resource Record", extra
);
1425 errormsg
= "mDNS_AddRecordToService";
1432 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, name
->c
, type
, data_len
, errormsg
, err
);
1437 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1438 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1440 // Check client parameter
1441 (void)unusedserver
; // Unused
1442 mStatus err
= mStatus_NoError
;
1443 const char *errormsg
= "Unknown";
1444 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1445 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1446 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1447 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1449 // Check other parameters
1450 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1452 ExtraRecordRef
*ref
= mallocL("ExtraRecordRef", sizeof(ExtraRecordRef
));
1453 if (!ref
) { LogMsg("ERROR: malloc"); return mStatus_NoMemoryErr
; }
1455 ref
->localRef
= AddExtraRecord(x
, &x
->ls
, client
, type
, data
, data_len
, ttl
);
1456 if (!ref
->localRef
) { freeL("ExtraRecordRef", ref
); *reference
= (natural_t
)NULL
; return mStatus_UnknownErr
; }
1458 if (x
->gs
) ref
->globalRef
= AddExtraRecord(x
, x
->gs
, client
, type
, data
, data_len
, ttl
); // return success even if global case fails
1459 else ref
->globalRef
= NULL
;
1461 // Succeeded: Wrap up and return
1462 ref
->next
= x
->ExtraRefList
;
1463 x
->ExtraRefList
= ref
;
1464 *reference
= (natural_t
)ref
;
1465 return mStatus_NoError
;
1468 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, x
->name
.c
, type
, data_len
, errormsg
, err
);
1469 return mStatus_UnknownErr
;
1472 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1475 if (OldRData
!= &rr
->rdatastorage
)
1476 freeL("Old RData", OldRData
);
1479 mDNSlocal mStatus
UpdateRecord(ServiceRecordSet
*srs
, mach_port_t client
, AuthRecord
*rr
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1481 // Check client parameter
1482 mStatus err
= mStatus_NoError
;
1483 const char *errormsg
= "Unknown";
1484 domainname
*name
= (domainname
*)"";
1486 name
= &srs
->RR_SRV
.resrec
.name
;
1488 unsigned int size
= sizeof(RDataBody
);
1489 if (size
< data_len
)
1492 // Allocate memory, and handle failure
1493 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1494 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1496 // Fill in new length, and data
1497 newrdata
->MaxRDLength
= size
;
1498 memcpy(&newrdata
->u
, data
, data_len
);
1501 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
1502 client
, srs
->RR_SRV
.resrec
.name
.c
, data_len
);
1504 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1507 errormsg
= "mDNS_Update";
1508 freeL("RData", newrdata
);
1511 return(mStatus_NoError
);
1514 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client
, name
->c
, data_len
, errormsg
, err
);
1519 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1520 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1522 // Check client parameter
1523 mStatus err
= mStatus_NoError
;
1524 const char *errormsg
= "Unknown";
1525 domainname
*name
= (domainname
*)"";
1526 AuthRecord
*gRR
, *lRR
;
1528 (void)unusedserver
; // unused
1529 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1530 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1531 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1532 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1534 // Check other parameters
1535 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1537 // Find the record we're updating. NULL reference means update the primary TXT record
1540 lRR
= &x
->ls
.RR_TXT
;
1541 gRR
= x
->gs
? &x
->gs
->RR_TXT
: NULL
;
1545 ExtraRecordRef
*ref
;
1546 for (ref
= x
->ExtraRefList
; ref
; ref
= ref
->next
)
1547 if (ref
== (ExtraRecordRef
*)reference
) break;
1548 if (!ref
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1549 lRR
= &ref
->localRef
->r
;
1550 gRR
= ref
->globalRef
? &ref
->globalRef
->r
: NULL
;
1553 err
= UpdateRecord(&x
->ls
, client
, lRR
, data
, data_len
, ttl
);
1556 if (gRR
) UpdateRecord(x
->gs
, client
, gRR
, data
, data_len
, ttl
); // don't return error if global fails
1557 return mStatus_NoError
;
1560 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
1564 mDNSlocal mStatus
RemoveRecord(ServiceRecordSet
*srs
, ExtraResourceRecord
*extra
, mach_port_t client
)
1566 domainname
*name
= &srs
->RR_SRV
.resrec
.name
;
1567 mStatus err
= mStatus_NoError
;
1568 const char *errormsg
= "Unknown";
1571 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client
, srs
->RR_SRV
.resrec
.name
.c
);
1573 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, srs
, extra
);
1574 if (err
) { errormsg
= "mDNS_RemoveRecordFromService (No such record)"; goto fail
; }
1576 // Succeeded: Wrap up and return
1577 if (extra
->r
.resrec
.rdata
!= &extra
->r
.rdatastorage
)
1578 freeL("Extra RData", extra
->r
.resrec
.rdata
);
1579 freeL("ExtraResourceRecord", extra
);
1580 return(mStatus_NoError
);
1583 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X) failed: %s", client
, name
->c
, errormsg
, err
);
1587 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1588 natural_t reference
)
1590 // Check client parameter
1591 (void)unusedserver
; // Unused
1592 mStatus err
= mStatus_NoError
;
1593 const char *errormsg
= "Unknown";
1594 ExtraRecordRef
*ref
, *prev
= NULL
;
1595 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1596 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1597 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1598 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1600 ref
= x
->ExtraRefList
;
1603 if (ref
== (ExtraRecordRef
*)ref
) break;
1608 if (!ref
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such reference"; goto fail
; }
1609 err
= RemoveRecord(&x
->ls
, ref
->localRef
, client
);
1610 if (x
->gs
&& ref
->globalRef
) RemoveRecord(x
->gs
, ref
->globalRef
, client
); // don't return error if this fails
1612 // delete the ref struct
1613 if (prev
) prev
->next
= ref
->next
;
1614 else x
->ExtraRefList
= ref
->next
;
1616 freeL("ExtraRecordRef", ref
);
1620 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client
, reference
, errormsg
, err
);
1624 //*************************************************************************************************************
1627 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1629 mig_reply_error_t
*request
= msg
;
1630 mig_reply_error_t
*reply
;
1631 mach_msg_return_t mr
;
1633 (void)port
; // Unused
1634 (void)size
; // Unused
1635 (void)info
; // Unused
1637 /* allocate a reply buffer */
1638 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
1640 /* call the MiG server routine */
1641 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
1643 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
1645 if (reply
->RetCode
== MIG_NO_REPLY
)
1648 * This return code is a little tricky -- it appears that the
1649 * demux routine found an error of some sort, but since that
1650 * error would not normally get returned either to the local
1651 * user or the remote one, we pretend it's ok.
1653 CFAllocatorDeallocate(NULL
, reply
);
1658 * destroy any out-of-line data in the request buffer but don't destroy
1659 * the reply port right (since we need that to send an error message).
1661 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
1662 mach_msg_destroy(&request
->Head
);
1665 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
1667 /* no reply port, so destroy the reply */
1668 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
1669 mach_msg_destroy(&reply
->Head
);
1670 CFAllocatorDeallocate(NULL
, reply
);
1677 * We don't want to block indefinitely because the client
1678 * isn't receiving messages from the reply port.
1679 * If we have a send-once right for the reply port, then
1680 * this isn't a concern because the send won't block.
1681 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1682 * To avoid falling off the kernel's fast RPC path unnecessarily,
1683 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1686 options
= MACH_SEND_MSG
;
1687 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
1688 options
|= MACH_SEND_TIMEOUT
;
1690 mr
= mach_msg(&reply
->Head
, /* msg */
1691 options
, /* option */
1692 reply
->Head
.msgh_size
, /* send_size */
1694 MACH_PORT_NULL
, /* rcv_name */
1695 MACH_MSG_TIMEOUT_NONE
, /* timeout */
1696 MACH_PORT_NULL
); /* notify */
1698 /* Has a message error occurred? */
1701 case MACH_SEND_INVALID_DEST
:
1702 case MACH_SEND_TIMED_OUT
:
1703 /* the reply can't be delivered, so destroy it */
1704 mach_msg_destroy(&reply
->Head
);
1708 /* Includes success case. */
1712 CFAllocatorDeallocate(NULL
, reply
);
1715 mDNSlocal kern_return_t
registerBootstrapService()
1717 kern_return_t status
;
1718 mach_port_t service_send_port
, service_rcv_port
;
1720 debugf("Registering Bootstrap Service");
1723 * See if our service name is already registered and if we have privilege to check in.
1725 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1726 if (status
== KERN_SUCCESS
)
1729 * If so, we must be a followup instance of an already defined server. In that case,
1730 * the bootstrap port we inherited from our parent is the server's privilege port, so set
1731 * that in case we have to unregister later (which requires the privilege port).
1733 server_priv_port
= bootstrap_port
;
1734 restarting_via_mach_init
= TRUE
;
1736 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
1738 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
1739 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
1740 if (status
!= KERN_SUCCESS
) return status
;
1742 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
1743 if (status
!= KERN_SUCCESS
)
1745 mach_port_deallocate(mach_task_self(), server_priv_port
);
1749 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1750 if (status
!= KERN_SUCCESS
)
1752 mach_port_deallocate(mach_task_self(), server_priv_port
);
1753 mach_port_deallocate(mach_task_self(), service_send_port
);
1756 assert(service_send_port
== service_rcv_port
);
1760 * We have no intention of responding to requests on the service port. We are not otherwise
1761 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
1762 * So, we can dispose of all the rights we have for the service port. We don't destroy the
1763 * send right for the server's privileged bootstrap port - in case we have to unregister later.
1765 mach_port_destroy(mach_task_self(), service_rcv_port
);
1769 mDNSlocal kern_return_t
destroyBootstrapService()
1771 debugf("Destroying Bootstrap Service");
1772 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
1775 mDNSlocal
void ExitCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1777 (void)port
; // Unused
1778 (void)msg
; // Unused
1779 (void)size
; // Unused
1780 (void)info
; // Unused
1783 int rrcache_active = 0;
1784 for (rr = mDNSStorage.rrcache; rr; rr=rr->next) if (CacheRRActive(&mDNSStorage, rr)) rrcache_active++;
1785 debugf("ExitCallback: RR Cache now using %d records, %d active", mDNSStorage.rrcache_used, rrcache_active);
1788 LogMsgIdent(mDNSResponderVersionString
, "stopping");
1790 debugf("ExitCallback: destroyBootstrapService");
1791 if (!mDNS_DebugMode
)
1792 destroyBootstrapService();
1794 debugf("ExitCallback: Aborting MIG clients");
1795 while (DNSServiceDomainEnumerationList
)
1796 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
1797 while (DNSServiceBrowserList
)
1798 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
1799 while (DNSServiceResolverList
)
1800 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
1801 while (DNSServiceRegistrationList
)
1802 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
1804 debugf("ExitCallback: mDNS_Close");
1805 mDNS_Close(&mDNSStorage
);
1806 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
1810 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
1811 mDNSlocal
void HandleSIGTERM(int signal
)
1813 (void)signal
; // Unused
1815 debugf("SIGINT/SIGTERM");
1816 mach_msg_header_t header
;
1817 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
1818 header
.msgh_remote_port
= exit_m_port
;
1819 header
.msgh_local_port
= MACH_PORT_NULL
;
1820 header
.msgh_size
= sizeof(header
);
1822 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
1823 { LogMsg("HandleSIGTERM: mach_msg_send failed; Exiting immediately."); exit(-1); }
1826 mDNSlocal
void INFOCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1828 (void)port
; // Unused
1829 (void)msg
; // Unused
1830 (void)size
; // Unused
1831 (void)info
; // Unused
1832 DNSServiceDomainEnumeration
*e
;
1833 DNSServiceBrowser
*b
;
1834 DNSServiceResolver
*l
;
1835 DNSServiceRegistration
*r
;
1836 NetworkInterfaceInfoOSX
*i
;
1839 mDNSu32 CacheUsed
= 0, CacheActive
= 0;
1840 mDNSs32 now
= mDNSPlatformTimeNow();
1842 LogMsgIdent(mDNSResponderVersionString
, "---- BEGIN STATE LOG ----");
1844 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1846 mDNSu32 SlotUsed
= 0;
1847 for (rr
= mDNSStorage
.rrcache_hash
[slot
]; rr
; rr
=rr
->next
)
1849 mDNSs32 remain
= rr
->resrec
.rroriginalttl
- (now
- rr
->TimeRcvd
) / mDNSPlatformOneSecond
;
1852 if (rr
->CRActiveQuestion
) CacheActive
++;
1853 LogMsgNoIdent("%s%6ld %-6s%-6s%s", rr
->CRActiveQuestion
? "*" : " ", remain
, DNSTypeName(rr
->resrec
.rrtype
),
1854 ((NetworkInterfaceInfoOSX
*)rr
->resrec
.InterfaceID
)->ifa_name
, GetRRDisplayString(&mDNSStorage
, rr
));
1855 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1857 if (mDNSStorage
.rrcache_used
[slot
] != SlotUsed
)
1858 LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", mDNSStorage
.rrcache_used
[slot
], SlotUsed
);
1860 if (mDNSStorage
.rrcache_totalused
!= CacheUsed
)
1861 LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", mDNSStorage
.rrcache_totalused
, CacheUsed
);
1862 if (mDNSStorage
.rrcache_active
!= CacheActive
)
1863 LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", mDNSStorage
.rrcache_active
, CacheActive
);
1864 LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed
, CacheActive
);
1866 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
1867 LogMsgNoIdent("%5d: DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
1869 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
1871 DNSServiceBrowserQuestion
*qptr
;
1872 for (qptr
= b
->qlist
; qptr
; qptr
= qptr
->next
)
1873 LogMsgNoIdent("%5d: ServiceBrowse %##s", b
->ClientMachPort
, qptr
->q
.qname
.c
);
1875 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
1876 LogMsgNoIdent("%5d: ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
1878 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1880 LogMsgNoIdent("%5d: ServiceRegistration %##s %u", r
->ClientMachPort
, r
->ls
.RR_SRV
.resrec
.name
.c
, mDNSVal16(r
->ls
.RR_SRV
.resrec
.rdata
->u
.srv
.port
));
1881 if (r
->gs
) LogMsgNoIdent("%5d: ServiceRegistration %##s %u", r
->ClientMachPort
, r
->gs
->RR_SRV
.resrec
.name
.c
, mDNSVal16(r
->gs
->RR_SRV
.resrec
.rdata
->u
.srv
.port
));
1886 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
1889 LogMsgNoIdent("Interface: %s %5s(%lu) DORMANT",
1890 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
);
1892 LogMsgNoIdent("Interface: %s %5s(%lu) %s %s %2d %s %2d InterfaceID %p %s %s %#a",
1893 i
->sa_family
== AF_INET
? "v4" : i
->sa_family
== AF_INET6
? "v6" : "??", i
->ifa_name
, i
->scope_id
,
1894 i
->ifinfo
.InterfaceActive
? "Active" : " ",
1895 i
->ifinfo
.IPv4Available
? "v4" : " ", i
->ss
.sktv4
,
1896 i
->ifinfo
.IPv6Available
? "v6" : " ", i
->ss
.sktv6
,
1897 i
->ifinfo
.InterfaceID
,
1898 i
->ifinfo
.Advertise
? "Adv" : " ",
1899 i
->ifinfo
.McastTxRx
? "TxRx" : " ",
1903 LogMsgIdent(mDNSResponderVersionString
, "---- END STATE LOG ----");
1906 mDNSlocal
void HandleSIGINFO(int signal
)
1908 (void)signal
; // Unused
1909 mach_msg_header_t header
;
1910 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
1911 header
.msgh_remote_port
= info_m_port
;
1912 header
.msgh_local_port
= MACH_PORT_NULL
;
1913 header
.msgh_size
= sizeof(header
);
1915 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
1916 LogMsg("HandleSIGINFO: mach_msg_send failed; No state log will be generated.");
1919 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
1922 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
1923 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
1924 CFMachPortRef e_port
= CFMachPortCreate(NULL
, ExitCallback
, NULL
, NULL
);
1925 CFMachPortRef i_port
= CFMachPortCreate(NULL
, INFOCallback
, NULL
, NULL
);
1926 mach_port_t m_port
= CFMachPortGetPort(s_port
);
1927 char *MachServerName
= mDNSMacOSXSystemBuildNumber(NULL
) < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
1928 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
1929 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
1930 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
1931 CFRunLoopSourceRef e_rls
= CFMachPortCreateRunLoopSource(NULL
, e_port
, 0);
1932 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
1937 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
1939 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
1943 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
1944 rrcachestorage
, RR_CACHE_SIZE
,
1945 mDNS_Init_AdvertiseLocalAddresses
,
1946 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
1948 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
1950 client_death_port
= CFMachPortGetPort(d_port
);
1951 exit_m_port
= CFMachPortGetPort(e_port
);
1952 info_m_port
= CFMachPortGetPort(i_port
);
1954 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
1955 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
1956 CFRunLoopAddSource(CFRunLoopGetCurrent(), e_rls
, kCFRunLoopDefaultMode
);
1957 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
1962 if (mDNS_DebugMode
) printf("Service registered with Mach Port %d\n", m_port
);
1963 err
= udsserver_init(&mDNSStorage
);
1964 if (err
) { LogMsg("Daemon start: udsserver_init failed"); return err
; }
1968 mDNSlocal mDNSs32
mDNSDaemonIdle(void)
1970 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1971 mDNSs32 nextevent
= mDNS_Execute(&mDNSStorage
);
1973 mDNSs32 now
= mDNSPlatformTimeNow();
1975 // 2. Deliver any waiting browse messages to clients
1976 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1980 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
1981 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
1982 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
1983 DNSServiceBrowser
*x
= b
;
1985 if (x
->results
) // Try to deliver the list of results
1989 DNSServiceBrowserResult
*const r
= x
->results
;
1991 domainname type
, domain
;
1992 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
1993 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
1994 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
1995 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
1996 ConvertDomainLabelToCString_unescaped(&name
, cname
);
1997 ConvertDomainNameToCString(&type
, ctype
);
1998 ConvertDomainNameToCString(&domain
, cdom
);
1999 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
2000 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
2001 // If we failed to send the mach message, try again in one second
2002 if (status
== MACH_SEND_TIMED_OUT
)
2004 if (nextevent
- now
> mDNSPlatformOneSecond
)
2005 nextevent
= now
+ mDNSPlatformOneSecond
;
2010 x
->lastsuccess
= now
;
2011 x
->results
= x
->results
->next
;
2012 freeL("DNSServiceBrowserResult", r
);
2015 // If this client hasn't read a single message in the last 60 seconds, abort it
2016 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
2017 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
2021 DNSServiceResolver
*l
;
2022 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
2023 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
2026 LogMsg("%5d: DNSServiceResolver(%##s) active for over two minutes. "
2027 "This places considerable burden on the network.", l
->ClientMachPort
, l
->i
.name
.c
);
2033 mDNSexport
int main(int argc
, char **argv
)
2036 kern_return_t status
;
2038 for (i
=1; i
<argc
; i
++)
2040 if (!strcmp(argv
[i
], "-d")) mDNS_DebugMode
= mDNStrue
;
2043 signal(SIGINT
, HandleSIGTERM
); // SIGINT is what you get for a Ctrl-C
2044 signal(SIGTERM
, HandleSIGTERM
);
2045 signal(SIGINFO
, HandleSIGINFO
);
2047 // Register the server with mach_init for automatic restart only during normal (non-debug) mode
2048 if (!mDNS_DebugMode
) registerBootstrapService();
2050 if (!mDNS_DebugMode
&& !restarting_via_mach_init
)
2051 exit(0); /* mach_init will restart us immediately as a daemon */
2053 if (!mDNS_DebugMode
)
2055 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
2058 // Avoid unnecessarily duplicating a file descriptor to itself
2059 if (fd
!= STDIN_FILENO
) (void)dup2(fd
, STDIN_FILENO
);
2060 if (fd
!= STDOUT_FILENO
) (void)dup2(fd
, STDOUT_FILENO
);
2061 if (fd
!= STDERR_FILENO
) (void)dup2(fd
, STDERR_FILENO
);
2062 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
)
2067 // First do the all the initialization we need root privilege for, before we change to user "nobody"
2068 LogMsgIdent(mDNSResponderVersionString
, "starting");
2069 status
= mDNSDaemonInitialize();
2071 // Now that we're finished with anything privileged, switch over to running as "nobody"
2072 const struct passwd
*pw
= getpwnam("nobody");
2076 setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
2081 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
2083 // This is the main work loop:
2084 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
2085 // (2) Then we make sure we've delivered all waiting browse messages to our clients
2086 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
2087 // (4) On wakeup we first process *all* events
2088 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
2089 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
2091 // 1. Before going into a blocking wait call and letting our process to go sleep,
2092 // call mDNSDaemonIdle to allow any deferred work to be completed.
2093 mDNSs32 nextevent
= mDNSDaemonIdle();
2094 nextevent
= udsserver_idle(nextevent
);
2096 // 2. Work out how long we expect to sleep before the next scheduled task
2097 mDNSs32 ticks
= nextevent
- mDNSPlatformTimeNow();
2098 static mDNSs32 RepeatedBusy
= 0; // Debugging sanity check, to guard against CPU spins
2104 if (++RepeatedBusy
>= mDNSPlatformOneSecond
* 10)
2105 { LogMsg("Task Scheduling Error: Continuously busy for the last ten seconds"); RepeatedBusy
= 0; }
2107 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
2109 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
2110 // (a) our next wakeup time, or (b) an event occurs.
2111 // The 'true' parameter makes it return after handling any event that occurs
2112 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
2113 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
2115 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
2117 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
2118 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
2121 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
2125 LogMsg("ERROR: CFRunLoopRun Exiting.");
2126 mDNS_Close(&mDNSStorage
);
2129 if (!mDNS_DebugMode
) destroyBootstrapService();
2134 // uds_daemon.c support routines /////////////////////////////////////////////
2136 // We keep a list of client-supplied event sources in PosixEventSource records
2137 struct CFSocketEventSource
2139 udsEventCallback Callback
;
2142 struct CFSocketEventSource
*Next
;
2143 CFSocketRef SocketRef
;
2144 CFRunLoopSourceRef RLS
;
2146 typedef struct CFSocketEventSource CFSocketEventSource
;
2148 static GenLinkedList gEventSources
; // linked list of CFSocketEventSource's
2150 static void cf_callback(CFSocketRef s _UNUSED
, CFSocketCallBackType t _UNUSED
, CFDataRef dr _UNUSED
, const void *c _UNUSED
, void *i
)
2151 // Called by CFSocket when data appears on socket
2153 CFSocketEventSource
*source
= (CFSocketEventSource
*) i
;
2154 source
->Callback(source
->Context
);
2157 mStatus
udsSupportAddFDToEventLoop(int fd
, udsEventCallback callback
, void *context
)
2158 // Arrange things so that callback is called with context when data appears on fd
2160 CFSocketEventSource
*newSource
;
2161 CFSocketContext cfContext
= { 0, NULL
, NULL
, NULL
, NULL
};
2163 if (gEventSources
.LinkOffset
== 0)
2164 InitLinkedList(&gEventSources
, offsetof(CFSocketEventSource
, Next
));
2166 if (fd
>= FD_SETSIZE
|| fd
< 0)
2167 return mStatus_UnsupportedErr
;
2168 if (callback
== NULL
)
2169 return mStatus_BadParamErr
;
2171 newSource
= (CFSocketEventSource
*) calloc(1, sizeof *newSource
);
2172 if (NULL
== newSource
)
2173 return mStatus_NoMemoryErr
;
2175 newSource
->Callback
= callback
;
2176 newSource
->Context
= context
;
2179 cfContext
.info
= newSource
;
2180 if ( NULL
!= (newSource
->SocketRef
= CFSocketCreateWithNative(kCFAllocatorDefault
, fd
, kCFSocketReadCallBack
,
2181 cf_callback
, &cfContext
)) &&
2182 NULL
!= (newSource
->RLS
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, newSource
->SocketRef
, 0)))
2184 CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource
->RLS
, kCFRunLoopDefaultMode
);
2185 AddToTail(&gEventSources
, newSource
);
2189 if (newSource
->SocketRef
)
2191 CFSocketInvalidate(newSource
->SocketRef
); // automatically closes socket
2192 CFRelease(newSource
->SocketRef
);
2194 return mStatus_NoMemoryErr
;
2197 return mStatus_NoError
;
2200 mStatus
udsSupportRemoveFDFromEventLoop(int fd
)
2201 // Reverse what was done in udsSupportAddFDToEventLoop().
2203 CFSocketEventSource
*iSource
;
2205 for (iSource
=(CFSocketEventSource
*)gEventSources
.Head
; iSource
; iSource
= iSource
->Next
)
2207 if (fd
== iSource
->fd
)
2209 RemoveFromList(&gEventSources
, iSource
);
2210 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource
->RLS
, kCFRunLoopDefaultMode
);
2211 CFRunLoopSourceInvalidate(iSource
->RLS
);
2212 CFRelease(iSource
->RLS
);
2213 CFSocketInvalidate(iSource
->SocketRef
);
2214 CFRelease(iSource
->SocketRef
);
2216 return mStatus_NoError
;
2219 return mStatus_NoSuchNameErr
;
2222 // For convenience when using the "strings" command, this is the last thing in the file
2223 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";