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.134.2.3 2003/12/12 01:21:30 cheshire
40 <rdar://problem/3491108> mDNSResponder should not run as root
42 Revision 1.134.2.2 2003/12/05 00:03:35 cheshire
43 <rdar://problem/3487869> Use buffer size MAX_ESCAPED_DOMAIN_NAME instead of 256
45 Revision 1.134.2.1 2003/12/03 11:00:09 cheshire
46 Update "mDNSResponderVersion" mechanism to allow dots so we can do mDNSResponder-58.1 for SUPan
48 Revision 1.134 2003/08/21 20:01:37 cheshire
49 <rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
51 Revision 1.133 2003/08/20 23:39:31 cheshire
52 <rdar://problem/3344098> Review syslog messages, and remove as appropriate
54 Revision 1.132 2003/08/20 01:44:56 cheshire
55 Fix errors in LogOperation() calls (only used for debugging)
57 Revision 1.131 2003/08/19 05:39:43 cheshire
58 <rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
60 Revision 1.130 2003/08/16 03:39:01 cheshire
61 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
63 Revision 1.129 2003/08/15 20:16:03 cheshire
64 <rdar://problem/3366590> mDNSResponder takes too much RPRVT
65 We want to avoid touching the rdata pages, so we don't page them in.
66 1. RDLength was stored with the rdata, which meant touching the page just to find the length.
67 Moved this from the RData to the ResourceRecord object.
68 2. To avoid unnecessarily touching the rdata just to compare it,
69 compute a hash of the rdata and store the hash in the ResourceRecord object.
71 Revision 1.128 2003/08/14 19:30:36 cheshire
72 <rdar://problem/3378473> Include list of cache records in SIGINFO output
74 Revision 1.127 2003/08/14 02:18:21 cheshire
75 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
77 Revision 1.126 2003/08/12 19:56:25 cheshire
80 Revision 1.125 2003/08/08 18:36:04 cheshire
81 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
83 Revision 1.124 2003/07/25 18:28:23 cheshire
84 Minor fix to error messages in syslog: Display string parameters with quotes
86 Revision 1.123 2003/07/23 17:45:28 cheshire
87 <rdar://problem/3339388> mDNSResponder leaks a bit
88 Don't allocate memory for the reply until after we've verified that the reply is valid
90 Revision 1.122 2003/07/23 00:00:04 cheshire
93 Revision 1.121 2003/07/20 03:38:51 ksekar
95 Completed support for Unix-domain socket based API.
97 Revision 1.120 2003/07/18 00:30:00 cheshire
98 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
100 Revision 1.119 2003/07/17 19:08:58 cheshire
101 <rdar://problem/3332153> Remove calls to enable obsolete UDS code
103 Revision 1.118 2003/07/15 21:12:28 cheshire
104 Added extra debugging checks in validatelists() (not used in final shipping version)
106 Revision 1.117 2003/07/15 01:55:15 cheshire
107 <rdar://problem/3315777> Need to implement service registration with subtypes
109 Revision 1.116 2003/07/02 21:19:51 cheshire
110 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
112 Revision 1.115 2003/07/02 02:41:24 cheshire
113 <rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
115 Revision 1.114 2003/07/01 21:10:20 cheshire
116 Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
118 Revision 1.113 2003/06/28 17:27:43 vlubet
119 <rdar://problem/3221246> Redirect standard input, standard output, and
120 standard error file descriptors to /dev/null just like any other
123 Revision 1.112 2003/06/25 23:42:19 ksekar
124 Bug #: <rdar://problem/3249292>: Feature: New Rendezvous APIs (#7875)
125 Reviewed by: Stuart Cheshire
126 Added files necessary to implement Unix domain sockets based enhanced
127 Rendezvous APIs, and integrated with existing Mach-port based daemon.
129 Revision 1.111 2003/06/11 01:02:43 cheshire
130 <rdar://problem/3287858> mDNSResponder binary compatibility
131 Make single binary that can run on both Jaguar and Panther.
133 Revision 1.110 2003/06/10 01:14:11 cheshire
134 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
136 Revision 1.109 2003/06/06 19:53:43 cheshire
137 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
138 (Global search-and-replace; no functional change to code execution.)
140 Revision 1.108 2003/06/06 14:08:06 cheshire
141 For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
143 Revision 1.107 2003/05/29 05:44:55 cheshire
144 Minor fixes to log messages
146 Revision 1.106 2003/05/27 18:30:55 cheshire
147 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
148 Dean Reece suggested SIGINFO is more appropriate than SIGHUP
150 Revision 1.105 2003/05/26 03:21:29 cheshire
151 Tidy up address structure naming:
152 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
153 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
154 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
156 Revision 1.104 2003/05/26 00:42:06 cheshire
157 <rdar://problem/3268876> Temporarily include mDNSResponder version in packets
159 Revision 1.103 2003/05/23 23:07:44 cheshire
160 <rdar://problem/3268199> Must not write to stderr when running as daemon
162 Revision 1.102 2003/05/22 01:32:31 cheshire
163 Fix typo in Log message format string
165 Revision 1.101 2003/05/22 00:26:55 cheshire
166 <rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
167 Modify error message to explain that this is technically legal, but may indicate a bug.
169 Revision 1.100 2003/05/21 21:02:24 ksekar
170 Bug #: <rdar://problem/3247035>: Service should be prefixed
171 Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
172 Mach message port to "com.apple.mDNSResponder.
174 Revision 1.99 2003/05/21 17:33:49 cheshire
175 Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
177 Revision 1.98 2003/05/20 00:33:07 cheshire
178 <rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
179 SIGHUP now writes state summary to syslog
181 Revision 1.97 2003/05/08 00:19:08 cheshire
182 <rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
184 Revision 1.96 2003/05/07 22:10:46 cheshire
185 <rdar://problem/3250330> Add a few more error logging messages
187 Revision 1.95 2003/05/07 19:20:17 cheshire
188 <rdar://problem/3251391> Add version number to mDNSResponder builds
190 Revision 1.94 2003/05/07 00:28:18 cheshire
191 <rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
193 Revision 1.93 2003/05/06 00:00:49 cheshire
194 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
196 Revision 1.92 2003/04/04 20:38:57 cheshire
201 #include <mach/mach.h>
202 #include <mach/mach_error.h>
203 #include <servers/bootstrap.h>
204 #include <sys/types.h>
210 #include "DNSServiceDiscoveryRequestServer.h"
211 #include "DNSServiceDiscoveryReply.h"
213 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
214 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
216 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
220 //*************************************************************************************************************
223 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
224 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
225 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
226 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
227 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
229 //*************************************************************************************************************
232 mDNSexport mDNS mDNSStorage
;
233 static mDNS_PlatformSupport PlatformStorage
;
234 #define RR_CACHE_SIZE 64
235 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
236 static const char PID_FILE
[] = "/var/run/mDNSResponder.pid";
238 static const char kmDNSBootstrapName
[] = "com.apple.mDNSResponderRestart";
239 static mach_port_t client_death_port
= MACH_PORT_NULL
;
240 static mach_port_t exit_m_port
= MACH_PORT_NULL
;
241 static mach_port_t info_m_port
= MACH_PORT_NULL
;
242 static mach_port_t server_priv_port
= MACH_PORT_NULL
;
244 // mDNS Mach Message Timeout, in milliseconds.
245 // We need this to be short enough that we don't deadlock the mDNSResponder if a client
246 // fails to service its mach message queue, but long enough to give a well-written
247 // client a chance to service its mach message queue without getting cut off.
248 // Empirically, 50ms seems to work, so we set the timeout to 250ms to give
249 // even extra-slow clients a fair chance before we cut them off.
250 #define MDNS_MM_TIMEOUT 250
252 static int restarting_via_mach_init
= 0;
260 //*************************************************************************************************************
261 // Active client list structures
263 typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration
;
264 struct DNSServiceDomainEnumeration_struct
266 DNSServiceDomainEnumeration
*next
;
267 mach_port_t ClientMachPort
;
268 DNSQuestion dom
; // Question asking for domains
269 DNSQuestion def
; // Question asking for default domain
272 typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult
;
273 struct DNSServiceBrowserResult_struct
275 DNSServiceBrowserResult
*next
;
280 typedef struct DNSServiceBrowser_struct DNSServiceBrowser
;
281 struct DNSServiceBrowser_struct
283 DNSServiceBrowser
*next
;
284 mach_port_t ClientMachPort
;
286 DNSServiceBrowserResult
*results
;
290 typedef struct DNSServiceResolver_struct DNSServiceResolver
;
291 struct DNSServiceResolver_struct
293 DNSServiceResolver
*next
;
294 mach_port_t ClientMachPort
;
300 typedef struct DNSServiceRegistration_struct DNSServiceRegistration
;
301 struct DNSServiceRegistration_struct
303 DNSServiceRegistration
*next
;
304 mach_port_t ClientMachPort
;
309 // Don't add any fields after ServiceRecordSet.
310 // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
313 static DNSServiceDomainEnumeration
*DNSServiceDomainEnumerationList
= NULL
;
314 static DNSServiceBrowser
*DNSServiceBrowserList
= NULL
;
315 static DNSServiceResolver
*DNSServiceResolverList
= NULL
;
316 static DNSServiceRegistration
*DNSServiceRegistrationList
= NULL
;
318 //*************************************************************************************************************
319 // General Utility Functions
321 #if MACOSX_MDNS_MALLOC_DEBUGGING
323 char _malloc_options
[] = "AXZ";
325 static void validatelists(mDNS
*const m
)
327 DNSServiceDomainEnumeration
*e
;
328 DNSServiceBrowser
*b
;
329 DNSServiceResolver
*l
;
330 DNSServiceRegistration
*r
;
336 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
337 if (e
->ClientMachPort
== 0 || e
->ClientMachPort
== (mach_port_t
)~0)
338 LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e
, e
->ClientMachPort
);
340 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
341 if (b
->ClientMachPort
== 0 || b
->ClientMachPort
== (mach_port_t
)~0)
342 LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b
, b
->ClientMachPort
);
344 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
345 if (l
->ClientMachPort
== 0 || l
->ClientMachPort
== (mach_port_t
)~0)
346 LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l
, l
->ClientMachPort
);
348 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
349 if (r
->ClientMachPort
== 0 || r
->ClientMachPort
== (mach_port_t
)~0)
350 LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r
, r
->ClientMachPort
);
352 for (rr
= m
->ResourceRecords
; rr
; rr
=rr
->next
)
353 if (rr
->RecordType
== 0 || rr
->RecordType
== 0xFF)
354 LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr
, rr
->RecordType
);
356 for (rr
= m
->DuplicateRecords
; rr
; rr
=rr
->next
)
357 if (rr
->RecordType
== 0 || rr
->RecordType
== 0xFF)
358 LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr
, rr
->RecordType
);
360 for (q
= m
->Questions
; q
; q
=q
->next
)
361 if (q
->ThisQInterval
== (mDNSs32
)~0)
362 LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q
, q
->ThisQInterval
);
364 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
365 for (cr
= mDNSStorage
.rrcache_hash
[slot
]; cr
; cr
=cr
->next
)
366 if (cr
->RecordType
== 0 || cr
->RecordType
== 0xFF)
367 LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot
, rr
, rr
->RecordType
);
370 void *mallocL(char *msg
, unsigned int size
)
372 unsigned long *mem
= malloc(size
+8);
375 LogMsg("malloc( %s : %d ) failed", msg
, size
);
380 LogMalloc("malloc( %s : %lu ) = %p", msg
, size
, &mem
[2]);
383 //bzero(&mem[2], size);
384 memset(&mem
[2], 0xFF, size
);
385 validatelists(&mDNSStorage
);
390 void freeL(char *msg
, void *x
)
393 LogMsg("free( %s @ NULL )!", msg
);
396 unsigned long *mem
= ((unsigned long *)x
) - 2;
397 if (mem
[0] != 0xDEAD1234)
398 { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg
, &mem
[2]); return; }
400 { LogMsg("free( %s : %ld @ %p) too big!", msg
, mem
[1], &mem
[2]); return; }
401 LogMalloc("free( %s : %ld @ %p)", msg
, mem
[1], &mem
[2]);
402 //bzero(mem, mem[1]+8);
403 memset(mem
, 0xFF, mem
[1]+8);
404 validatelists(&mDNSStorage
);
411 //*************************************************************************************************************
412 // Client Death Detection
414 mDNSlocal
void FreeDNSServiceRegistration(DNSServiceRegistration
*x
)
418 ExtraResourceRecord
*extras
= x
->s
.Extras
;
419 x
->s
.Extras
= x
->s
.Extras
->next
;
420 if (extras
->r
.resrec
.rdata
!= &extras
->r
.rdatastorage
)
421 freeL("Extra RData", extras
->r
.resrec
.rdata
);
422 freeL("ExtraResourceRecord", extras
);
425 if (x
->s
.RR_TXT
.resrec
.rdata
!= &x
->s
.RR_TXT
.rdatastorage
)
426 freeL("TXT RData", x
->s
.RR_TXT
.resrec
.rdata
);
428 if (x
->s
.SubTypes
) freeL("ServiceSubTypes", x
->s
.SubTypes
);
430 freeL("DNSServiceRegistration", x
);
433 // AbortClient finds whatever client is identified by the given Mach port,
434 // stops whatever operation that client was doing, and frees its memory.
435 // In the case of a service registration, the actual freeing may be deferred
436 // until we get the mStatus_MemFree message, if necessary
437 mDNSlocal
void AbortClient(mach_port_t ClientMachPort
, void *m
)
439 DNSServiceDomainEnumeration
**e
= &DNSServiceDomainEnumerationList
;
440 DNSServiceBrowser
**b
= &DNSServiceBrowserList
;
441 DNSServiceResolver
**l
= &DNSServiceResolverList
;
442 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
444 while (*e
&& (*e
)->ClientMachPort
!= ClientMachPort
) e
= &(*e
)->next
;
447 DNSServiceDomainEnumeration
*x
= *e
;
450 LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->dom
.qname
.c
, m
, x
);
451 else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort
, x
->dom
.qname
.c
);
452 mDNS_StopGetDomains(&mDNSStorage
, &x
->dom
);
453 mDNS_StopGetDomains(&mDNSStorage
, &x
->def
);
454 freeL("DNSServiceDomainEnumeration", x
);
458 while (*b
&& (*b
)->ClientMachPort
!= ClientMachPort
) b
= &(*b
)->next
;
461 DNSServiceBrowser
*x
= *b
;
464 LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->q
.qname
.c
, m
, x
);
465 else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort
, x
->q
.qname
.c
);
466 mDNS_StopBrowse(&mDNSStorage
, &x
->q
);
469 DNSServiceBrowserResult
*r
= x
->results
;
470 x
->results
= x
->results
->next
;
471 freeL("DNSServiceBrowserResult", r
);
473 freeL("DNSServiceBrowser", x
);
477 while (*l
&& (*l
)->ClientMachPort
!= ClientMachPort
) l
= &(*l
)->next
;
480 DNSServiceResolver
*x
= *l
;
483 LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->i
.name
.c
, m
, x
);
484 else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort
, x
->i
.name
.c
);
485 mDNS_StopResolveService(&mDNSStorage
, &x
->q
);
486 freeL("DNSServiceResolver", x
);
490 while (*r
&& (*r
)->ClientMachPort
!= ClientMachPort
) r
= &(*r
)->next
;
493 DNSServiceRegistration
*x
= *r
;
495 x
->autorename
= mDNSfalse
;
497 LogMsg("%5d: DNSServiceRegistration(%##s) STOP; WARNING m %p != x %p", ClientMachPort
, x
->s
.RR_SRV
.resrec
.name
.c
, m
, x
);
498 else LogOperation("%5d: DNSServiceRegistration(%##s) STOP", ClientMachPort
, x
->s
.RR_SRV
.resrec
.name
.c
);
499 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
500 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
501 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
502 // the list, so we should go ahead and free the memory right now
503 if (mDNS_DeregisterService(&mDNSStorage
, &x
->s
) != mStatus_NoError
)
504 FreeDNSServiceRegistration(x
);
508 LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort
);
511 #define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
513 mDNSlocal
void AbortClientWithLogMessage(mach_port_t c
, char *reason
, char *msg
, void *m
)
515 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
516 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
517 DNSServiceResolver
*l
= DNSServiceResolverList
;
518 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
519 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
520 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
521 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
522 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
523 if (e
) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c
, e
->dom
.qname
.c
, reason
, msg
);
524 else if (b
) LogMsg("%5d: Browser(%##s) %s%s", c
, b
->q
.qname
.c
, reason
, msg
);
525 else if (l
) LogMsg("%5d: Resolver(%##s) %s%s", c
, l
->i
.name
.c
, reason
, msg
);
526 else if (r
) LogMsg("%5d: Registration(%##s) %s%s", c
, r
->s
.RR_SRV
.resrec
.name
.c
, reason
, msg
);
527 else LogMsg("%5d: (%s) %s, but no record of client can be found!", c
, reason
, msg
);
532 mDNSlocal mDNSBool
CheckForExistingClient(mach_port_t c
)
534 DNSServiceDomainEnumeration
*e
= DNSServiceDomainEnumerationList
;
535 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
536 DNSServiceResolver
*l
= DNSServiceResolverList
;
537 DNSServiceRegistration
*r
= DNSServiceRegistrationList
;
538 while (e
&& e
->ClientMachPort
!= c
) e
= e
->next
;
539 while (b
&& b
->ClientMachPort
!= c
) b
= b
->next
;
540 while (l
&& l
->ClientMachPort
!= c
) l
= l
->next
;
541 while (r
&& r
->ClientMachPort
!= c
) r
= r
->next
;
542 if (e
) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c
, e
->dom
.qname
.c
);
543 if (b
) LogMsg("%5d: Browser(%##s) already exists!", c
, b
->q
.qname
.c
);
544 if (l
) LogMsg("%5d: Resolver(%##s) already exists!", c
, l
->i
.name
.c
);
545 if (r
) LogMsg("%5d: Registration(%##s) already exists!", c
, r
->s
.RR_SRV
.resrec
.name
.c
);
546 return(e
|| b
|| l
|| r
);
549 mDNSlocal
void ClientDeathCallback(CFMachPortRef unusedport
, void *voidmsg
, CFIndex size
, void *info
)
551 mach_msg_header_t
*msg
= (mach_msg_header_t
*)voidmsg
;
552 (void)unusedport
; // Unused
553 (void)size
; // Unused
554 (void)info
; // Unused
555 if (msg
->msgh_id
== MACH_NOTIFY_DEAD_NAME
)
557 const mach_dead_name_notification_t
*const deathMessage
= (mach_dead_name_notification_t
*)msg
;
558 AbortClient(deathMessage
->not_port
, NULL
);
560 /* Deallocate the send right that came in the dead name notification */
561 mach_port_destroy( mach_task_self(), deathMessage
->not_port
);
565 mDNSlocal
void EnableDeathNotificationForClient(mach_port_t ClientMachPort
, void *m
)
568 kern_return_t r
= mach_port_request_notification(mach_task_self(), ClientMachPort
, MACH_NOTIFY_DEAD_NAME
, 0,
569 client_death_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &prev
);
570 // If the port already died while we were thinking about it, then abort the operation right away
571 if (r
!= KERN_SUCCESS
)
572 AbortClientWithLogMessage(ClientMachPort
, "died/deallocated before we could enable death notification", "", m
);
575 //*************************************************************************************************************
576 // Domain Enumeration
578 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
580 kern_return_t status
;
582 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
583 DNSServiceDomainEnumerationReplyResultType rt
;
584 DNSServiceDomainEnumeration
*x
= (DNSServiceDomainEnumeration
*)question
->QuestionContext
;
586 debugf("FoundDomain: %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
587 if (answer
->rrtype
!= kDNSType_PTR
) return;
588 if (!x
) { debugf("FoundDomain: DNSServiceDomainEnumeration is NULL"); return; }
592 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyAddDomain
;
593 else rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
597 if (question
== &x
->dom
) rt
= DNSServiceDomainEnumerationReplyRemoveDomain
;
601 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
602 x
->ClientMachPort
, x
->dom
.qname
.c
, answer
->rdata
->u
.name
.c
,
603 !AddRecord
? "RemoveDomain" :
604 question
== &x
->dom
? "AddDomain" : "AddDomainDefault");
606 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, buffer
);
607 status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, buffer
, 0, MDNS_MM_TIMEOUT
);
608 if (status
== MACH_SEND_TIMED_OUT
)
609 AbortBlockedClient(x
->ClientMachPort
, "enumeration", x
);
612 mDNSexport kern_return_t
provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
615 // Check client parameter
616 (void)unusedserver
; // Unused
617 mStatus err
= mStatus_NoError
;
618 const char *errormsg
= "Unknown";
619 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
620 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
622 mDNS_DomainType dt1
= regDom
? mDNS_DomainTypeRegistration
: mDNS_DomainTypeBrowse
;
623 mDNS_DomainType dt2
= regDom
? mDNS_DomainTypeRegistrationDefault
: mDNS_DomainTypeBrowseDefault
;
624 const DNSServiceDomainEnumerationReplyResultType rt
= DNSServiceDomainEnumerationReplyAddDomainDefault
;
626 // Allocate memory, and handle failure
627 DNSServiceDomainEnumeration
*x
= mallocL("DNSServiceDomainEnumeration", sizeof(*x
));
628 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
630 // Set up object, and link into list
631 x
->ClientMachPort
= client
;
632 x
->next
= DNSServiceDomainEnumerationList
;
633 DNSServiceDomainEnumerationList
= x
;
635 // Generate initial response
636 verbosedebugf("%5d: Enumerate %s Domains", client
, regDom
? "Registration" : "Browsing");
637 // We always give local. as the initial default browse domain, and then look for more
638 kern_return_t status
= DNSServiceDomainEnumerationReply_rpc(x
->ClientMachPort
, rt
, "local.", 0, MDNS_MM_TIMEOUT
);
639 if (status
== MACH_SEND_TIMED_OUT
)
640 { AbortBlockedClient(x
->ClientMachPort
, "local enumeration", x
); return(mStatus_UnknownErr
); }
643 err
= mDNS_GetDomains(&mDNSStorage
, &x
->dom
, dt1
, mDNSInterface_Any
, FoundDomain
, x
);
644 if (!err
) err
= mDNS_GetDomains(&mDNSStorage
, &x
->def
, dt2
, mDNSInterface_Any
, FoundDomain
, x
);
645 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_GetDomains"; goto fail
; }
647 // Succeeded: Wrap up and return
648 LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client
, x
->dom
.qname
.c
);
649 EnableDeathNotificationForClient(client
, x
);
650 return(mStatus_NoError
);
653 LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client
, regDom
, errormsg
, err
);
657 //*************************************************************************************************************
658 // Browse for services
660 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
664 if (answer
->rrtype
!= kDNSType_PTR
)
665 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
668 domainname type
, domain
;
669 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
671 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
672 answer
->name
.c
, answer
->rdata
->u
.name
.c
);
676 DNSServiceBrowserResult
*x
= mallocL("DNSServiceBrowserResult", sizeof(*x
));
677 if (!x
) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer
->rdata
->u
.name
.c
); return; }
679 verbosedebugf("FoundInstance: %s %##s", AddRecord
? "Add" : "Rmv", answer
->rdata
->u
.name
.c
);
680 AssignDomainName(x
->result
, answer
->rdata
->u
.name
);
682 x
->resultType
= DNSServiceBrowserReplyAddInstance
;
683 else x
->resultType
= DNSServiceBrowserReplyRemoveInstance
;
686 DNSServiceBrowser
*browser
= (DNSServiceBrowser
*)question
->QuestionContext
;
687 DNSServiceBrowserResult
**p
= &browser
->results
;
688 while (*p
) p
= &(*p
)->next
;
692 mDNSexport kern_return_t
provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
693 DNSCString regtype
, DNSCString domain
)
695 // Check client parameter
696 (void)unusedserver
; // Unused
697 mStatus err
= mStatus_NoError
;
698 const char *errormsg
= "Unknown";
699 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
700 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
702 // Check other parameters
704 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
705 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Illegal domain"; goto badparam
; }
707 // Allocate memory, and handle failure
708 DNSServiceBrowser
*x
= mallocL("DNSServiceBrowser", sizeof(*x
));
709 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
711 // Set up object, and link into list
712 x
->ClientMachPort
= client
;
715 x
->next
= DNSServiceBrowserList
;
716 DNSServiceBrowserList
= x
;
719 LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", client
, t
.c
, d
.c
);
720 err
= mDNS_StartBrowse(&mDNSStorage
, &x
->q
, &t
, &d
, mDNSInterface_Any
, FoundInstance
, x
);
721 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartBrowse"; goto fail
; }
723 // Succeeded: Wrap up and return
724 EnableDeathNotificationForClient(client
, x
);
725 return(mStatus_NoError
);
728 err
= mStatus_BadParamErr
;
730 LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client
, regtype
, domain
, errormsg
, err
);
734 //*************************************************************************************************************
735 // Resolve Service Info
737 mDNSlocal
void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
739 kern_return_t status
;
740 DNSServiceResolver
*x
= (DNSServiceResolver
*)query
->ServiceInfoQueryContext
;
741 NetworkInterfaceInfoOSX
*ifx
= (NetworkInterfaceInfoOSX
*)query
->info
->InterfaceID
;
742 if (query
->info
->InterfaceID
== (mDNSInterfaceID
)~0) ifx
= mDNSNULL
;
743 struct sockaddr_storage interface
;
744 struct sockaddr_storage address
;
746 int i
, pstrlen
= query
->info
->TXTinfo
[0];
749 //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
751 if (query
->info
->TXTlen
> sizeof(cstring
)) return;
753 bzero(&interface
, sizeof(interface
));
754 bzero(&address
, sizeof(address
));
756 if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
758 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&interface
;
759 sin
->sin_len
= sizeof(*sin
);
760 sin
->sin_family
= AF_INET
;
762 sin
->sin_addr
.s_addr
= ifx
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
764 else if (ifx
&& ifx
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
)
766 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&interface
;
767 sin6
->sin6_len
= sizeof(*sin6
);
768 sin6
->sin6_family
= AF_INET6
;
769 sin6
->sin6_flowinfo
= 0;
771 sin6
->sin6_addr
= *(struct in6_addr
*)&ifx
->ifinfo
.ip
.ip
.v6
;
772 sin6
->sin6_scope_id
= ifx
->scope_id
;
775 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
777 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&address
;
778 sin
->sin_len
= sizeof(*sin
);
779 sin
->sin_family
= AF_INET
;
780 sin
->sin_port
= query
->info
->port
.NotAnInteger
;
781 sin
->sin_addr
.s_addr
= query
->info
->ip
.ip
.v4
.NotAnInteger
;
785 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&address
;
786 sin6
->sin6_len
= sizeof(*sin6
);
787 sin6
->sin6_family
= AF_INET6
;
788 sin6
->sin6_port
= query
->info
->port
.NotAnInteger
;
789 sin6
->sin6_flowinfo
= 0;
790 sin6
->sin6_addr
= *(struct in6_addr
*)&query
->info
->ip
.ip
.v6
;
791 sin6
->sin6_scope_id
= ifx
? ifx
->scope_id
: 0;
794 // The OS X DNSServiceResolverResolve() API is defined using a C-string,
795 // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
796 // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
797 // ASCII-1 characters are used in the C-string as boundary markers,
798 // to indicate the boundaries between the original constituent P-strings.
799 for (i
=1; i
<query
->info
->TXTlen
; i
++)
802 cstring
[i
-1] = query
->info
->TXTinfo
[i
];
806 pstrlen
= query
->info
->TXTinfo
[i
];
809 cstring
[i
-1] = 0; // Put the terminating NULL on the end
811 LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%d", x
->ClientMachPort
,
812 x
->i
.name
.c
, &query
->info
->ip
, (int)query
->info
->port
.b
[0] << 8 | query
->info
->port
.b
[1]);
813 status
= DNSServiceResolverReply_rpc(x
->ClientMachPort
,
814 (char*)&interface
, (char*)&address
, cstring
, 0, MDNS_MM_TIMEOUT
);
815 if (status
== MACH_SEND_TIMED_OUT
)
816 AbortBlockedClient(x
->ClientMachPort
, "resolve", x
);
819 mDNSexport kern_return_t
provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver
, mach_port_t client
,
820 DNSCString name
, DNSCString regtype
, DNSCString domain
)
822 // Check client parameter
823 (void)unusedserver
; // Unused
824 mStatus err
= mStatus_NoError
;
825 const char *errormsg
= "Unknown";
826 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
827 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
829 // Check other parameters
831 domainname t
, d
, srv
;
832 if (!name
[0] || !MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
833 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
834 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
835 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
837 // Allocate memory, and handle failure
838 DNSServiceResolver
*x
= mallocL("DNSServiceResolver", sizeof(*x
));
839 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
841 // Set up object, and link into list
842 x
->ClientMachPort
= client
;
843 x
->i
.InterfaceID
= mDNSInterface_Any
;
845 x
->ReportTime
= (mDNSPlatformTimeNow() + 130 * mDNSPlatformOneSecond
) | 1;
846 // Don't report errors for old iChat ("_ichat._tcp") service.
847 // New iChat ("_presence._tcp") uses DNSServiceQueryRecord() (from /usr/include/dns_sd.h) instead,
848 // and so should other applications that have valid reasons to be doing ongoing record monitoring.
849 if (SameDomainLabel(t
.c
, (mDNSu8
*)"\x6_ichat")) x
->ReportTime
= 0;
850 x
->next
= DNSServiceResolverList
;
851 DNSServiceResolverList
= x
;
854 LogOperation("%5d: DNSServiceResolver(%##s) START", client
, x
->i
.name
.c
);
855 err
= mDNS_StartResolveService(&mDNSStorage
, &x
->q
, &x
->i
, FoundInstanceInfo
, x
);
856 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_StartResolveService"; goto fail
; }
858 // Succeeded: Wrap up and return
859 EnableDeathNotificationForClient(client
, x
);
860 return(mStatus_NoError
);
863 err
= mStatus_BadParamErr
;
865 LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client
, name
, regtype
, domain
, errormsg
, err
);
869 //*************************************************************************************************************
872 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
874 DNSServiceRegistration
*x
= (DNSServiceRegistration
*)sr
->ServiceContext
;
876 if (result
== mStatus_NoError
)
878 kern_return_t status
;
879 LogOperation("%5d: DNSServiceRegistration(%##s) Name Registered", x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
);
880 status
= DNSServiceRegistrationReply_rpc(x
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
881 if (status
== MACH_SEND_TIMED_OUT
)
882 AbortBlockedClient(x
->ClientMachPort
, "registration success", x
);
885 else if (result
== mStatus_NameConflict
)
887 LogOperation("%5d: DNSServiceRegistration(%##s) Name Conflict", x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
);
888 // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
889 // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
891 mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
894 // If we get a name conflict, we tell the client about it, and then they are expected to dispose
895 // of their registration in the usual way (which we will catch via client death notification).
896 // If the Mach queue is full, we forcibly abort the client immediately.
897 kern_return_t status
= DNSServiceRegistrationReply_rpc(x
->ClientMachPort
, result
, MDNS_MM_TIMEOUT
);
898 if (status
== MACH_SEND_TIMED_OUT
)
899 AbortBlockedClient(x
->ClientMachPort
, "registration conflict", x
);
903 else if (result
== mStatus_MemFree
)
907 debugf("RegCallback renaming %#s to %#s", x
->name
.c
, mDNSStorage
.nicelabel
.c
);
908 x
->autorename
= mDNSfalse
;
909 x
->name
= mDNSStorage
.nicelabel
;
910 mDNS_RenameAndReregisterService(m
, &x
->s
, &x
->name
);
914 DNSServiceRegistration
**r
= &DNSServiceRegistrationList
;
915 while (*r
&& *r
!= x
) r
= &(*r
)->next
;
918 LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr
->RR_SRV
.resrec
.name
.c
);
921 LogOperation("%5d: DNSServiceRegistration(%##s) Memory Free", x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
);
922 FreeDNSServiceRegistration(x
);
927 LogMsg("%5d: DNSServiceRegistration(%##s) Unknown Result %ld",
928 x
->ClientMachPort
, sr
->RR_SRV
.resrec
.name
.c
, result
);
931 mDNSlocal
void CheckForDuplicateRegistrations(DNSServiceRegistration
*x
, domainname
*srv
, mDNSIPPort port
)
933 int count
= 1; // Start with the one we're planning to register, then see if there are any more
935 for (rr
= mDNSStorage
.ResourceRecords
; rr
; rr
=rr
->next
)
936 if (rr
->resrec
.rrtype
== kDNSType_SRV
&&
937 rr
->resrec
.rdata
->u
.srv
.port
.NotAnInteger
== port
.NotAnInteger
&&
938 SameDomainName(&rr
->resrec
.name
, srv
))
942 LogMsg("%5d: Client application registered %d identical instances of service %##s port %d.",
943 x
->ClientMachPort
, count
, srv
->c
, (int)port
.b
[0] << 8 | port
.b
[1]);
946 mDNSexport kern_return_t
provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver
, mach_port_t client
,
947 DNSCString name
, DNSCString regtype
, DNSCString domain
, int notAnIntPort
, DNSCString txtRecord
)
949 // Check client parameter
950 (void)unusedserver
; // Unused
951 mStatus err
= mStatus_NoError
;
952 const char *errormsg
= "Unknown";
953 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
954 if (CheckForExistingClient(client
)) { err
= mStatus_Invalid
; errormsg
= "Client id already in use"; goto fail
; }
956 // Check for sub-types after the service type
957 AuthRecord
*SubTypes
= mDNSNULL
;
958 mDNSu32 i
, NumSubTypes
= 0;
959 char *comma
= regtype
;
960 while (*comma
&& *comma
!= ',') comma
++;
961 if (*comma
) // If we found a comma...
963 *comma
= 0; // Overwrite the first comma with a nul
964 char *p
= comma
+ 1; // Start scanning from the next character
967 if ( !(*p
&& *p
!= ',')) { errormsg
= "Bad Service SubType"; goto badparam
; }
968 while (*p
&& *p
!= ',') p
++;
974 // Check other parameters
978 if (!name
[0]) n
= mDNSStorage
.nicelabel
;
979 else if (!MakeDomainLabelFromLiteralString(&n
, name
)) { errormsg
= "Bad Instance Name"; goto badparam
; }
980 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Bad Service Type"; goto badparam
; }
981 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Bad Domain"; goto badparam
; }
982 if (!ConstructServiceName(&srv
, &n
, &t
, &d
)) { errormsg
= "Bad Name"; goto badparam
; }
985 port
.NotAnInteger
= notAnIntPort
;
987 unsigned char txtinfo
[1024] = "";
988 unsigned int data_len
= 0;
989 unsigned int size
= sizeof(RDataBody
);
990 unsigned char *pstring
= &txtinfo
[data_len
];
991 char *ptr
= txtRecord
;
993 // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
994 // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
995 // Hence we have to convert the C-string to a P-string.
996 // ASCII-1 characters are allowed in the C-string as boundary markers,
997 // so that a single C-string can be used to represent one or more P-strings.
1000 if (++data_len
>= sizeof(txtinfo
)) { errormsg
= "TXT record too long"; goto badtxt
; }
1001 if (*ptr
== 1) // If this is our boundary marker, start a new P-string
1003 pstring
= &txtinfo
[data_len
];
1009 if (pstring
[0] == 255) { errormsg
= "TXT record invalid (component longer than 255)"; goto badtxt
; }
1010 pstring
[++pstring
[0]] = *ptr
++;
1015 if (size
< data_len
)
1018 // Allocate memory, and handle failure
1019 DNSServiceRegistration
*x
= mallocL("DNSServiceRegistration", sizeof(*x
) - sizeof(RDataBody
) + size
);
1020 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1024 SubTypes
= mallocL("ServiceSubTypes", NumSubTypes
* sizeof(AuthRecord
));
1025 if (!SubTypes
) { freeL("DNSServiceRegistration", x
); err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1026 for (i
= 0; i
< NumSubTypes
; i
++)
1028 comma
++; // Advance over the nul character
1029 MakeDomainNameFromDNSNameString(&SubTypes
[i
].resrec
.name
, comma
);
1030 while (*comma
) comma
++; // Advance comma to point to the next terminating nul
1034 // Set up object, and link into list
1035 x
->ClientMachPort
= client
;
1036 x
->autoname
= (!name
[0]);
1037 x
->autorename
= mDNSfalse
;
1039 x
->next
= DNSServiceRegistrationList
;
1040 DNSServiceRegistrationList
= x
;
1043 LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\") START", x
->ClientMachPort
, name
, regtype
, domain
);
1044 // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
1045 // a port number of zero. When two instances of the protected client are allowed to run on one
1046 // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
1047 if (port
.NotAnInteger
) CheckForDuplicateRegistrations(x
, &srv
, port
);
1049 err
= mDNS_RegisterService(&mDNSStorage
, &x
->s
,
1050 &x
->name
, &t
, &d
, // Name, type, domain
1051 mDNSNULL
, port
, // Host and port
1052 txtinfo
, data_len
, // TXT data, length
1053 SubTypes
, NumSubTypes
, // Subtypes
1054 mDNSInterface_Any
, // Interace ID
1055 RegCallback
, x
); // Callback and context
1057 if (err
) { AbortClient(client
, x
); errormsg
= "mDNS_RegisterService"; goto fail
; }
1059 // Succeeded: Wrap up and return
1060 EnableDeathNotificationForClient(client
, x
);
1061 return(mStatus_NoError
);
1064 LogMsg("%5d: TXT record: %.100s...", client
, txtRecord
);
1066 err
= mStatus_BadParamErr
;
1068 LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)",
1069 client
, name
, regtype
, domain
, notAnIntPort
, errormsg
, err
);
1073 mDNSlocal
void mDNS_StatusCallback(mDNS
*const m
, mStatus result
)
1076 if (result
== mStatus_ConfigChanged
)
1078 DNSServiceRegistration
*r
;
1079 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1080 if (r
->autoname
&& !SameDomainLabel(r
->name
.c
, mDNSStorage
.nicelabel
.c
))
1082 debugf("NetworkChanged renaming %#s to %#s", r
->name
.c
, mDNSStorage
.nicelabel
.c
);
1083 r
->autorename
= mDNStrue
;
1084 mDNS_DeregisterService(&mDNSStorage
, &r
->s
);
1087 else if (result
== mStatus_GrowCache
)
1089 // If we've run out of cache space, then double the total cache size and give the memory to mDNSCore
1090 mDNSu32 numrecords
= m
->rrcache_size
;
1091 CacheRecord
*storage
= mallocL("mStatus_GrowCache", sizeof(CacheRecord
) * numrecords
);
1092 if (storage
) mDNS_GrowCache(&mDNSStorage
, storage
, numrecords
);
1096 //*************************************************************************************************************
1097 // Add / Update / Remove records from existing Registration
1099 mDNSexport kern_return_t
provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1100 int type
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
, natural_t
*reference
)
1102 // Check client parameter
1103 (void)unusedserver
; // Unused
1104 mStatus err
= mStatus_NoError
;
1105 const char *errormsg
= "Unknown";
1106 domainname
*name
= (domainname
*)"";
1107 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1108 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1109 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1110 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1111 name
= &x
->s
.RR_SRV
.resrec
.name
;
1113 // Check other parameters
1114 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1115 unsigned int size
= sizeof(RDataBody
);
1116 if (size
< data_len
)
1119 // Allocate memory, and handle failure
1120 ExtraResourceRecord
*extra
= mallocL("ExtraResourceRecord", sizeof(*extra
) - sizeof(RDataBody
) + size
);
1121 if (!extra
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1123 // Fill in type, length, and data of new record
1124 extra
->r
.resrec
.rrtype
= type
;
1125 extra
->r
.rdatastorage
.MaxRDLength
= size
;
1126 extra
->r
.resrec
.rdlength
= data_len
;
1127 memcpy(&extra
->r
.rdatastorage
.u
.data
, data
, data_len
);
1130 LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
1131 client
, x
->s
.RR_SRV
.resrec
.name
.c
, type
, data_len
, extra
);
1132 err
= mDNS_AddRecordToService(&mDNSStorage
, &x
->s
, extra
, &extra
->r
.rdatastorage
, ttl
);
1133 *reference
= (natural_t
)extra
;
1134 if (err
) { errormsg
= "mDNS_AddRecordToService"; goto fail
; }
1136 // Succeeded: Wrap up and return
1137 return(mStatus_NoError
);
1140 LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client
, name
->c
, type
, data_len
, errormsg
, err
);
1144 mDNSlocal
void UpdateCallback(mDNS
*const m
, AuthRecord
*const rr
, RData
*OldRData
)
1147 if (OldRData
!= &rr
->rdatastorage
)
1148 freeL("Old RData", OldRData
);
1151 mDNSexport kern_return_t
provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1152 natural_t reference
, const char *data
, mach_msg_type_number_t data_len
, uint32_t ttl
)
1154 // Check client parameter
1155 (void)unusedserver
; // Unused
1156 mStatus err
= mStatus_NoError
;
1157 const char *errormsg
= "Unknown";
1158 domainname
*name
= (domainname
*)"";
1159 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1160 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1161 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1162 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1163 name
= &x
->s
.RR_SRV
.resrec
.name
;
1165 // Check other parameters
1166 if (data_len
> 8192) { err
= mStatus_BadParamErr
; errormsg
= "data_len > 8K"; goto fail
; }
1167 unsigned int size
= sizeof(RDataBody
);
1168 if (size
< data_len
)
1171 // Find the record we're updating. NULL reference means update the primary TXT record
1172 AuthRecord
*rr
= &x
->s
.RR_TXT
;
1173 if (reference
) // Scan our list to make sure we're updating a valid record that was previously added
1175 ExtraResourceRecord
*e
= x
->s
.Extras
;
1176 while (e
&& e
!= (ExtraResourceRecord
*)reference
) e
= e
->next
;
1177 if (!e
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such record"; goto fail
; }
1181 // Allocate memory, and handle failure
1182 RData
*newrdata
= mallocL("RData", sizeof(*newrdata
) - sizeof(RDataBody
) + size
);
1183 if (!newrdata
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
1185 // Fill in new length, and data
1186 newrdata
->MaxRDLength
= size
;
1187 memcpy(&newrdata
->u
, data
, data_len
);
1190 LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, new length %d)",
1191 client
, x
->s
.RR_SRV
.resrec
.name
.c
, reference
, data_len
);
1192 err
= mDNS_Update(&mDNSStorage
, rr
, ttl
, data_len
, newrdata
, UpdateCallback
);
1193 if (err
) { errormsg
= "mDNS_Update"; goto fail
; }
1195 // Succeeded: Wrap up and return
1196 return(mStatus_NoError
);
1199 LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client
, name
->c
, reference
, data_len
, errormsg
, err
);
1203 mDNSexport kern_return_t
provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver
, mach_port_t client
,
1204 natural_t reference
)
1206 // Check client parameter
1207 (void)unusedserver
; // Unused
1208 mStatus err
= mStatus_NoError
;
1209 const char *errormsg
= "Unknown";
1210 domainname
*name
= (domainname
*)"";
1211 if (client
== (mach_port_t
)-1) { err
= mStatus_Invalid
; errormsg
= "Client id -1 invalid"; goto fail
; }
1212 DNSServiceRegistration
*x
= DNSServiceRegistrationList
;
1213 while (x
&& x
->ClientMachPort
!= client
) x
= x
->next
;
1214 if (!x
) { err
= mStatus_BadReferenceErr
; errormsg
= "No such client"; goto fail
; }
1215 name
= &x
->s
.RR_SRV
.resrec
.name
;
1218 LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X)", client
, x
->s
.RR_SRV
.resrec
.name
.c
, reference
);
1219 ExtraResourceRecord
*extra
= (ExtraResourceRecord
*)reference
;
1220 err
= mDNS_RemoveRecordFromService(&mDNSStorage
, &x
->s
, extra
);
1221 if (err
) { errormsg
= "mDNS_RemoveRecordFromService (No such record)"; goto fail
; }
1223 // Succeeded: Wrap up and return
1224 if (extra
->r
.resrec
.rdata
!= &extra
->r
.rdatastorage
)
1225 freeL("Extra RData", extra
->r
.resrec
.rdata
);
1226 freeL("ExtraResourceRecord", extra
);
1227 return(mStatus_NoError
);
1230 LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%##s, %X) failed: %s (%ld)", client
, name
->c
, reference
, errormsg
, err
);
1234 //*************************************************************************************************************
1237 mDNSlocal
void DNSserverCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1239 mig_reply_error_t
*request
= msg
;
1240 mig_reply_error_t
*reply
;
1241 mach_msg_return_t mr
;
1243 (void)port
; // Unused
1244 (void)size
; // Unused
1245 (void)info
; // Unused
1247 /* allocate a reply buffer */
1248 reply
= CFAllocatorAllocate(NULL
, provide_DNSServiceDiscoveryRequest_subsystem
.maxsize
, 0);
1250 /* call the MiG server routine */
1251 (void) DNSServiceDiscoveryRequest_server(&request
->Head
, &reply
->Head
);
1253 if (!(reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (reply
->RetCode
!= KERN_SUCCESS
))
1255 if (reply
->RetCode
== MIG_NO_REPLY
)
1258 * This return code is a little tricky -- it appears that the
1259 * demux routine found an error of some sort, but since that
1260 * error would not normally get returned either to the local
1261 * user or the remote one, we pretend it's ok.
1263 CFAllocatorDeallocate(NULL
, reply
);
1268 * destroy any out-of-line data in the request buffer but don't destroy
1269 * the reply port right (since we need that to send an error message).
1271 request
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
1272 mach_msg_destroy(&request
->Head
);
1275 if (reply
->Head
.msgh_remote_port
== MACH_PORT_NULL
)
1277 /* no reply port, so destroy the reply */
1278 if (reply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
1279 mach_msg_destroy(&reply
->Head
);
1280 CFAllocatorDeallocate(NULL
, reply
);
1287 * We don't want to block indefinitely because the client
1288 * isn't receiving messages from the reply port.
1289 * If we have a send-once right for the reply port, then
1290 * this isn't a concern because the send won't block.
1291 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1292 * To avoid falling off the kernel's fast RPC path unnecessarily,
1293 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1296 options
= MACH_SEND_MSG
;
1297 if (MACH_MSGH_BITS_REMOTE(reply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
)
1298 options
|= MACH_SEND_TIMEOUT
;
1300 mr
= mach_msg(&reply
->Head
, /* msg */
1301 options
, /* option */
1302 reply
->Head
.msgh_size
, /* send_size */
1304 MACH_PORT_NULL
, /* rcv_name */
1305 MACH_MSG_TIMEOUT_NONE
, /* timeout */
1306 MACH_PORT_NULL
); /* notify */
1308 /* Has a message error occurred? */
1311 case MACH_SEND_INVALID_DEST
:
1312 case MACH_SEND_TIMED_OUT
:
1313 /* the reply can't be delivered, so destroy it */
1314 mach_msg_destroy(&reply
->Head
);
1318 /* Includes success case. */
1322 CFAllocatorDeallocate(NULL
, reply
);
1325 mDNSlocal kern_return_t
registerBootstrapService()
1327 kern_return_t status
;
1328 mach_port_t service_send_port
, service_rcv_port
;
1330 debugf("Registering Bootstrap Service");
1333 * See if our service name is already registered and if we have privilege to check in.
1335 status
= bootstrap_check_in(bootstrap_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1336 if (status
== KERN_SUCCESS
)
1339 * If so, we must be a followup instance of an already defined server. In that case,
1340 * the bootstrap port we inherited from our parent is the server's privilege port, so set
1341 * that in case we have to unregister later (which requires the privilege port).
1343 server_priv_port
= bootstrap_port
;
1344 restarting_via_mach_init
= TRUE
;
1346 else if (status
== BOOTSTRAP_UNKNOWN_SERVICE
)
1348 status
= bootstrap_create_server(bootstrap_port
, "/usr/sbin/mDNSResponder", getuid(),
1349 FALSE
/* relaunch immediately, not on demand */, &server_priv_port
);
1350 if (status
!= KERN_SUCCESS
) return status
;
1352 status
= bootstrap_create_service(server_priv_port
, (char*)kmDNSBootstrapName
, &service_send_port
);
1353 if (status
!= KERN_SUCCESS
)
1355 mach_port_deallocate(mach_task_self(), server_priv_port
);
1359 status
= bootstrap_check_in(server_priv_port
, (char*)kmDNSBootstrapName
, &service_rcv_port
);
1360 if (status
!= KERN_SUCCESS
)
1362 mach_port_deallocate(mach_task_self(), server_priv_port
);
1363 mach_port_deallocate(mach_task_self(), service_send_port
);
1366 assert(service_send_port
== service_rcv_port
);
1370 * We have no intention of responding to requests on the service port. We are not otherwise
1371 * a Mach port-based service. We are just using this mechanism for relaunch facilities.
1372 * So, we can dispose of all the rights we have for the service port. We don't destroy the
1373 * send right for the server's privileged bootstrap port - in case we have to unregister later.
1375 mach_port_destroy(mach_task_self(), service_rcv_port
);
1379 mDNSlocal kern_return_t
destroyBootstrapService()
1381 debugf("Destroying Bootstrap Service");
1382 return bootstrap_register(server_priv_port
, (char*)kmDNSBootstrapName
, MACH_PORT_NULL
);
1385 mDNSlocal
void ExitCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1387 (void)port
; // Unused
1388 (void)msg
; // Unused
1389 (void)size
; // Unused
1390 (void)info
; // Unused
1393 int rrcache_active = 0;
1394 for (rr = mDNSStorage.rrcache; rr; rr=rr->next) if (CacheRRActive(&mDNSStorage, rr)) rrcache_active++;
1395 debugf("ExitCallback: RR Cache now using %d records, %d active", mDNSStorage.rrcache_used, rrcache_active);
1398 LogMsg("%s stopping", mDNSResponderVersionString
);
1400 debugf("ExitCallback: destroyBootstrapService");
1402 destroyBootstrapService();
1404 debugf("ExitCallback: Aborting MIG clients");
1405 while (DNSServiceDomainEnumerationList
)
1406 AbortClient(DNSServiceDomainEnumerationList
->ClientMachPort
, DNSServiceDomainEnumerationList
);
1407 while (DNSServiceBrowserList
)
1408 AbortClient(DNSServiceBrowserList
->ClientMachPort
, DNSServiceBrowserList
);
1409 while (DNSServiceResolverList
)
1410 AbortClient(DNSServiceResolverList
->ClientMachPort
, DNSServiceResolverList
);
1411 while (DNSServiceRegistrationList
)
1412 AbortClient(DNSServiceRegistrationList
->ClientMachPort
, DNSServiceRegistrationList
);
1414 debugf("ExitCallback: mDNS_Close");
1415 mDNS_Close(&mDNSStorage
);
1417 if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
1422 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
1423 mDNSlocal
void HandleSIGTERM(int signal
)
1425 (void)signal
; // Unused
1427 debugf("SIGINT/SIGTERM");
1428 mach_msg_header_t header
;
1429 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
1430 header
.msgh_remote_port
= exit_m_port
;
1431 header
.msgh_local_port
= MACH_PORT_NULL
;
1432 header
.msgh_size
= sizeof(header
);
1434 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
1435 { LogMsg("HandleSIGTERM: mach_msg_send failed; Exiting immediately."); exit(-1); }
1438 mDNSlocal
void INFOCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
1440 (void)port
; // Unused
1441 (void)msg
; // Unused
1442 (void)size
; // Unused
1443 (void)info
; // Unused
1444 DNSServiceDomainEnumeration
*e
;
1445 DNSServiceBrowser
*b
;
1446 DNSServiceResolver
*l
;
1447 DNSServiceRegistration
*r
;
1450 mDNSu32 CacheUsed
= 0, CacheActive
= 0;
1452 LogMsg("%s ---- BEGIN STATE LOG ----", mDNSResponderVersionString
);
1454 for (slot
= 0; slot
< CACHE_HASH_SLOTS
; slot
++)
1455 for (rr
= mDNSStorage
.rrcache_hash
[slot
]; rr
; rr
=rr
->next
)
1458 if (rr
->CRActiveQuestion
) CacheActive
++;
1459 LogMsg("%s %-5s%-6s%s", rr
->CRActiveQuestion
? "Active: " : "Inactive:", DNSTypeName(rr
->resrec
.rrtype
),
1460 ((NetworkInterfaceInfoOSX
*)rr
->resrec
.InterfaceID
)->ifa_name
, GetRRDisplayString(&mDNSStorage
, rr
));
1461 usleep(1000); // Limit rate a little so we don't flood syslog too fast
1463 if (mDNSStorage
.rrcache_totalused
!= CacheUsed
)
1464 LogMsg("Cache use mismatch: rrcache_totalused is %lu, true count %lu", mDNSStorage
.rrcache_totalused
, CacheUsed
);
1465 if (mDNSStorage
.rrcache_active
!= CacheActive
)
1466 LogMsg("Cache use mismatch: rrcache_active is %lu, true count %lu", mDNSStorage
.rrcache_active
, CacheActive
);
1467 LogMsg("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed
, CacheActive
);
1469 for (e
= DNSServiceDomainEnumerationList
; e
; e
=e
->next
)
1470 LogMsg("%5d: DomainEnumeration %##s", e
->ClientMachPort
, e
->dom
.qname
.c
);
1472 for (b
= DNSServiceBrowserList
; b
; b
=b
->next
)
1473 LogMsg("%5d: ServiceBrowse %##s", b
->ClientMachPort
, b
->q
.qname
.c
);
1475 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
1476 LogMsg("%5d: ServiceResolve %##s", l
->ClientMachPort
, l
->i
.name
.c
);
1478 for (r
= DNSServiceRegistrationList
; r
; r
=r
->next
)
1479 LogMsg("%5d: ServiceRegistration %##s", r
->ClientMachPort
, r
->s
.RR_SRV
.resrec
.name
.c
);
1483 LogMsg("%s ---- END STATE LOG ----", mDNSResponderVersionString
);
1486 mDNSlocal
void HandleSIGINFO(int signal
)
1488 (void)signal
; // Unused
1489 mach_msg_header_t header
;
1490 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
1491 header
.msgh_remote_port
= info_m_port
;
1492 header
.msgh_local_port
= MACH_PORT_NULL
;
1493 header
.msgh_size
= sizeof(header
);
1495 if (mach_msg_send(&header
) != MACH_MSG_SUCCESS
)
1496 LogMsg("HandleSIGINFO: mach_msg_send failed; No state log will be generated.");
1499 mDNSlocal kern_return_t
mDNSDaemonInitialize(void)
1502 CFMachPortRef d_port
= CFMachPortCreate(NULL
, ClientDeathCallback
, NULL
, NULL
);
1503 CFMachPortRef s_port
= CFMachPortCreate(NULL
, DNSserverCallback
, NULL
, NULL
);
1504 CFMachPortRef e_port
= CFMachPortCreate(NULL
, ExitCallback
, NULL
, NULL
);
1505 CFMachPortRef i_port
= CFMachPortCreate(NULL
, INFOCallback
, NULL
, NULL
);
1506 mach_port_t m_port
= CFMachPortGetPort(s_port
);
1507 char *MachServerName
= mDNSMacOSXSystemBuildNumber(NULL
) < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
1508 kern_return_t status
= bootstrap_register(bootstrap_port
, MachServerName
, m_port
);
1509 CFRunLoopSourceRef d_rls
= CFMachPortCreateRunLoopSource(NULL
, d_port
, 0);
1510 CFRunLoopSourceRef s_rls
= CFMachPortCreateRunLoopSource(NULL
, s_port
, 0);
1511 CFRunLoopSourceRef e_rls
= CFMachPortCreateRunLoopSource(NULL
, e_port
, 0);
1512 CFRunLoopSourceRef i_rls
= CFMachPortCreateRunLoopSource(NULL
, i_port
, 0);
1517 LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
1519 LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status
), status
);
1523 err
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
1524 rrcachestorage
, RR_CACHE_SIZE
,
1525 mDNS_Init_AdvertiseLocalAddresses
,
1526 mDNS_StatusCallback
, mDNS_Init_NoInitCallbackContext
);
1527 if (err
) { LogMsg("Daemon start: mDNS_Init failed %ld", err
); return(err
); }
1529 client_death_port
= CFMachPortGetPort(d_port
);
1530 exit_m_port
= CFMachPortGetPort(e_port
);
1531 info_m_port
= CFMachPortGetPort(i_port
);
1533 CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls
, kCFRunLoopDefaultMode
);
1534 CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls
, kCFRunLoopDefaultMode
);
1535 CFRunLoopAddSource(CFRunLoopGetCurrent(), e_rls
, kCFRunLoopDefaultMode
);
1536 CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls
, kCFRunLoopDefaultMode
);
1541 if (debug_mode
) printf("Service registered with Mach Port %d\n", m_port
);
1543 err
= udsserver_init();
1544 if (err
) { LogMsg("Daemon start: udsserver_init failed"); return err
; }
1545 err
= udsserver_add_rl_source();
1546 if (err
) { LogMsg("Daemon start: udsserver_add_rl_source failed"); return err
; }
1551 mDNSlocal mDNSs32
mDNSDaemonIdle(void)
1553 // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
1554 mDNSs32 nextevent
= mDNS_Execute(&mDNSStorage
);
1556 mDNSs32 now
= mDNSPlatformTimeNow();
1558 // 2. Deliver any waiting browse messages to clients
1559 DNSServiceBrowser
*b
= DNSServiceBrowserList
;
1563 // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
1564 // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
1565 // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
1566 DNSServiceBrowser
*x
= b
;
1568 if (x
->results
) // Try to deliver the list of results
1572 DNSServiceBrowserResult
*const r
= x
->results
;
1574 domainname type
, domain
;
1575 DeconstructServiceName(&r
->result
, &name
, &type
, &domain
); // Don't need to check result; already validated in FoundInstance()
1576 char cname
[MAX_DOMAIN_LABEL
+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
1577 char ctype
[MAX_ESCAPED_DOMAIN_NAME
];
1578 char cdom
[MAX_ESCAPED_DOMAIN_NAME
];
1579 ConvertDomainLabelToCString_unescaped(&name
, cname
);
1580 ConvertDomainNameToCString(&type
, ctype
);
1581 ConvertDomainNameToCString(&domain
, cdom
);
1582 DNSServiceDiscoveryReplyFlags flags
= (r
->next
) ? DNSServiceDiscoverReplyFlagsMoreComing
: 0;
1583 kern_return_t status
= DNSServiceBrowserReply_rpc(x
->ClientMachPort
, r
->resultType
, cname
, ctype
, cdom
, flags
, 1);
1584 // If we failed to send the mach message, try again in one second
1585 if (status
== MACH_SEND_TIMED_OUT
)
1587 if (nextevent
- now
> mDNSPlatformOneSecond
)
1588 nextevent
= now
+ mDNSPlatformOneSecond
;
1593 x
->lastsuccess
= now
;
1594 x
->results
= x
->results
->next
;
1595 freeL("DNSServiceBrowserResult", r
);
1598 // If this client hasn't read a single message in the last 60 seconds, abort it
1599 if (now
- x
->lastsuccess
>= 60 * mDNSPlatformOneSecond
)
1600 AbortBlockedClient(x
->ClientMachPort
, "browse", x
);
1604 DNSServiceResolver
*l
;
1605 for (l
= DNSServiceResolverList
; l
; l
=l
->next
)
1606 if (l
->ReportTime
&& now
- l
->ReportTime
>= 0)
1609 LogMsg("%5d: DNSServiceResolver(%##s) has remained active for over two minutes. "
1610 "This places considerable burden on the network.", l
->ClientMachPort
, l
->i
.name
.c
);
1616 mDNSexport
int main(int argc
, char **argv
)
1619 kern_return_t status
;
1622 for (i
=1; i
<argc
; i
++)
1624 if (!strcmp(argv
[i
], "-d")) debug_mode
= 1;
1627 signal(SIGINT
, HandleSIGTERM
); // SIGINT is what you get for a Ctrl-C
1628 signal(SIGTERM
, HandleSIGTERM
);
1629 signal(SIGINFO
, HandleSIGINFO
);
1631 // Register the server with mach_init for automatic restart only during debug mode
1633 registerBootstrapService();
1635 if (!debug_mode
&& !restarting_via_mach_init
)
1636 exit(0); /* mach_init will restart us immediately as a daemon */
1638 // Unlike deamon(), mach_init does redirect standard file descriptors to /dev/null
1641 int fd
= open(_PATH_DEVNULL
, O_RDWR
, 0);
1644 // Avoid to unnecessarily duplicate a file descriptor to itself
1645 if (fd
!= STDIN_FILENO
) (void)dup2(fd
, STDIN_FILENO
);
1646 if (fd
!= STDOUT_FILENO
) (void)dup2(fd
, STDOUT_FILENO
);
1647 if (fd
!= STDERR_FILENO
) (void)dup2(fd
, STDERR_FILENO
);
1648 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
)
1653 fp
= fopen(PID_FILE
, "w");
1656 fprintf(fp
, "%d\n", getpid());
1660 LogMsg("%s starting", mDNSResponderVersionString
);
1661 status
= mDNSDaemonInitialize();
1663 // Now that we're finished with anything privileged, switch over to running as "nobody"
1664 const struct passwd
*pw
= getpwnam( "nobody");
1666 setuid( pw
->pw_uid
);
1668 status
= mStatus_Incompatible
; // refuse to run as root
1673 int RunLoopStatus
= kCFRunLoopRunTimedOut
;
1675 // This is the main work loop:
1676 // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
1677 // (2) Then we make sure we've delivered all waiting browse messages to our clients
1678 // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
1679 // (4) On wakeup we first process *all* events
1680 // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
1681 while (RunLoopStatus
== kCFRunLoopRunTimedOut
)
1683 // 1. Before going into a blocking wait call and letting our process to go sleep,
1684 // call mDNSDaemonIdle to allow any deferred work to be completed.
1685 mDNSs32 nextevent
= mDNSDaemonIdle();
1687 nextevent
= udsserver_idle(nextevent
);
1690 // 2. Work out how long we expect to sleep before the next scheduled task
1691 mDNSs32 ticks
= nextevent
- mDNSPlatformTimeNow();
1692 if (ticks
< 1) ticks
= 1;
1693 CFAbsoluteTime interval
= (CFAbsoluteTime
)ticks
/ (CFAbsoluteTime
)mDNSPlatformOneSecond
;
1695 // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
1696 // (a) our next wakeup time, or (b) an event occurs.
1697 // The 'true' parameter makes it return after handling any event that occurs
1698 // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
1699 verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents
, ticks
);
1701 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, interval
, true);
1703 // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
1704 while (RunLoopStatus
== kCFRunLoopRunHandledSource
)
1707 RunLoopStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 0.0, true);
1711 LogMsg("ERROR: CFRunLoopRun Exiting.");
1712 mDNS_Close(&mDNSStorage
);
1715 destroyBootstrapService();
1720 // For convenience when using the "strings" command, this is the last thing in the file
1721 mDNSexport
const char mDNSResponderVersionString
[] = STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";