2 * Copyright (c) 2002-2004 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@
23 Change History (most recent first):
25 $Log: DNSServices.c,v $
26 Revision 1.32 2004/12/16 20:13:02 cheshire
27 <rdar://problem/3324626> Cache memory management improvements
29 Revision 1.31 2004/10/19 21:33:23 cheshire
30 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
31 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
32 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
34 Revision 1.30 2004/09/17 01:08:58 cheshire
35 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
36 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
37 declared in that file are ONLY appropriate to single-address-space embedded applications.
38 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
40 Revision 1.29 2004/09/17 00:31:53 cheshire
41 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
43 Revision 1.28 2004/09/16 01:58:25 cheshire
46 Revision 1.27 2004/07/13 21:24:28 rpantos
47 Fix for <rdar://problem/3701120>.
49 Revision 1.26 2004/06/05 00:04:27 cheshire
50 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
52 Revision 1.25 2004/04/08 09:31:17 bradley
53 Renamed local variable to avoid hiding a system global in some libraries.
55 Revision 1.24 2004/01/30 02:56:34 bradley
56 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
58 Revision 1.23 2004/01/24 23:57:29 cheshire
59 Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
61 Revision 1.22 2003/12/17 21:12:15 bradley
62 <rdar://problem/3491823>: Use the default .local domain when registering with an empty domain.
64 Revision 1.21 2003/11/20 22:29:56 cheshire
65 Don't need to use MAX_ESCAPED_DOMAIN_LABEL for the name part -- that's not escaped
67 Revision 1.20 2003/11/14 21:27:09 cheshire
68 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
69 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
71 Revision 1.19 2003/11/14 20:59:10 cheshire
72 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
73 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
75 Revision 1.18 2003/11/14 19:18:34 cheshire
76 Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
78 Revision 1.17 2003/10/31 12:16:03 bradley
79 Added support for providing the resolved host name to the callback.
81 Revision 1.16 2003/10/16 09:16:39 bradley
82 Unified address copying to fix a problem with IPv6 resolves not being passed up as IPv6.
84 Revision 1.15 2003/08/20 06:44:24 bradley
85 Updated to latest internal version of the mDNSCore code: Added support for interface
86 specific registrations; Added support for no-such-service registrations; Added support for host
87 name registrations; Added support for host proxy and service proxy registrations; Added support for
88 registration record updates (e.g. TXT record updates); Added support for using either a single C
89 string TXT record, a raw, pre-formatted TXT record potentially containing multiple character string
90 entries, or a C-string containing a Mac OS X-style \001-delimited set of TXT record character
91 strings; Added support in resolve callbacks for providing both a simplified C-string for TXT records
92 and a ptr/size for the raw TXT record data; Added utility routines for dynamically building TXT
93 records from a variety of sources (\001-delimited, individual strings, etc.) and converting TXT
94 records to various formats for use in apps; Added utility routines to validate DNS names, DNS
95 service types, and TXT records; Moved to portable address representation unions (byte-stream vs host
96 order integer) for consistency, to avoid swapping between host and network byte order, and for IPv6
97 support; Removed dependence on modified mDNSCore: define structures and prototypes locally; Added
98 support for automatically renaming services on name conflicts; Detect and correct TXT records from
99 old versions of mDNS that treated a TXT record as an arbitrary block of data, but prevent other
100 malformed TXT records from being accepted; Added many more error codes; Added complete HeaderDoc for
101 all constants, structures, typedefs, macros, and functions. Various other minor cleanup and fixes.
103 Revision 1.14 2003/08/14 02:19:56 cheshire
104 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
106 Revision 1.13 2003/08/12 19:56:29 cheshire
109 Revision 1.12 2003/07/23 00:00:04 cheshire
112 Revision 1.11 2003/07/15 01:55:17 cheshire
113 <rdar://problem/3315777> Need to implement service registration with subtypes
115 Revision 1.10 2003/07/02 21:20:10 cheshire
116 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
118 Revision 1.9 2003/05/26 03:21:30 cheshire
119 Tidy up address structure naming:
120 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
121 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
122 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
124 Revision 1.8 2003/05/06 00:00:51 cheshire
125 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
127 Revision 1.7 2003/03/27 03:30:57 cheshire
128 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
129 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
131 1. Make mDNS_DeregisterInterface() safe to call from a callback
132 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
133 (it never really needed to deregister the interface at all)
135 Revision 1.6 2003/03/22 02:57:45 cheshire
136 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
138 Revision 1.5 2003/02/20 00:59:04 cheshire
139 Brought Windows code up to date so it complies with
140 Josh Graessley's interface changes for IPv6 support.
141 (Actual support for IPv6 on Windows will come later.)
143 Revision 1.4 2002/09/21 20:44:56 zarzycki
146 Revision 1.3 2002/09/20 08:36:50 bradley
147 Fixed debug messages to output the correct information when resolving.
149 Revision 1.2 2002/09/20 05:58:01 bradley
150 DNS Services for Windows
159 #include <CoreServices/CoreServices.h>
162 #include "mDNSEmbeddedAPI.h"
164 #include "DNSServices.h"
171 #pragma mark == Preprocessor ==
174 //===========================================================================================================================
176 //===========================================================================================================================
178 #if( defined( _MSC_VER ) )
179 #pragma warning( disable:4068 ) // Disable "unknown pragma" warning for "pragma unused".
180 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
184 #pragma mark == Constants ==
187 //===========================================================================================================================
189 //===========================================================================================================================
191 #define DEBUG_NAME "[DNSServices] "
195 kDNSInitializeValidFlags
= kDNSFlagAdvertise
,
199 kDNSBrowserCreateValidFlags
= 0,
200 kDNSBrowserReleaseValidFlags
= 0,
201 kDNSBrowserStartDomainSearchValidFlags
= kDNSBrowserFlagRegistrationDomainsOnly
,
202 kDNSBrowserStopDomainSearchValidFlags
= 0,
203 kDNSBrowserStartServiceSearchValidFlags
= kDNSBrowserFlagAutoResolve
,
204 kDNSBrowserStopServiceSearchValidFlags
= 0,
208 kDNSResolverCreateValidFlags
= kDNSResolverFlagOneShot
|
209 kDNSResolverFlagOnlyIfUnique
|
210 kDNSResolverFlagAutoReleaseByName
,
211 kDNSResolverReleaseValidFlags
= 0,
213 // Service Registration
215 kDNSRegistrationCreateValidFlags
= kDNSRegistrationFlagPreFormattedTextRecord
|
216 kDNSRegistrationFlagAutoRenameOnConflict
,
217 kDNSNoSuchServiceRegistrationCreateValidFlags
= 0,
218 kDNSRegistrationReleaseValidFlags
= 0,
219 kDNSRegistrationUpdateValidFlags
= 0,
221 kDNSRegistrationFlagPrivateNoSuchService
= ( 1 << 16 ),
223 // Domain Registration
225 kDNSDomainRegistrationCreateValidFlags
= 0,
226 kDNSDomainRegistrationReleaseValidFlags
= 0,
230 kDNSHostRegistrationCreateValidFlags
= kDNSHostRegistrationFlagOnlyIfNotFound
|
231 kDNSHostRegistrationFlagAutoRenameOnConflict
,
232 kDNSHostRegistrationReleaseValidFlags
= 0
235 #define kDNSCountCacheEntryCountDefault 64
238 #pragma mark == Structures ==
241 //===========================================================================================================================
243 //===========================================================================================================================
247 typedef struct DNSBrowser DNSBrowser
;
251 DNSBrowserFlags flags
;
252 DNSBrowserCallBack callback
;
253 void * callbackContext
;
254 mDNSBool isDomainBrowsing
;
255 DNSQuestion domainQuestion
;
256 DNSQuestion defaultDomainQuestion
;
257 DNSBrowserFlags domainSearchFlags
;
258 mDNSBool isServiceBrowsing
;
259 DNSQuestion serviceBrowseQuestion
;
260 DNSBrowserFlags serviceSearchFlags
;
261 char searchDomain
[ 256 ];
262 char searchServiceType
[ 256 ];
267 typedef struct DNSResolver DNSResolver
;
271 DNSResolverFlags flags
;
272 DNSResolverCallBack callback
;
273 void * callbackContext
;
275 ServiceInfoQuery query
;
277 mDNSBool isResolving
;
278 char resolveName
[ 256 ];
279 char resolveType
[ 256 ];
280 char resolveDomain
[ 256 ];
285 typedef struct DNSRegistration DNSRegistration
;
286 struct DNSRegistration
288 DNSRegistration
* next
;
289 DNSRegistrationFlags flags
;
290 DNSRegistrationCallBack callback
;
291 void * callbackContext
;
292 char interfaceName
[ 256 ];
293 ServiceRecordSet set
;
295 // WARNING: Do not add fields after the ServiceRecordSet. This is where oversized TXT record space is allocated.
298 // Domain Registration
300 typedef struct DNSDomainRegistration DNSDomainRegistration
;
301 struct DNSDomainRegistration
303 DNSDomainRegistration
* next
;
304 DNSDomainRegistrationFlags flags
;
308 // Domain Registration
310 typedef struct DNSHostRegistration DNSHostRegistration
;
311 struct DNSHostRegistration
313 DNSHostRegistration
* next
;
317 DNSHostRegistrationCallBack callback
;
318 void * callbackContext
;
319 DNSHostRegistrationFlags flags
;
320 char interfaceName
[ 256 ];
326 #pragma mark == Macros ==
329 //===========================================================================================================================
331 //===========================================================================================================================
333 // Emulate Mac OS debugging macros for non-Mac platforms.
335 #if( !TARGET_OS_MAC )
336 #define check(assertion)
337 #define check_string( assertion, cstring )
338 #define check_noerr(err)
339 #define check_noerr_string( error, cstring )
340 #define debug_string( cstring )
341 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
342 #define require_string( assertion, label, string ) require(assertion, label)
343 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
344 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
345 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
346 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
350 #pragma mark == Prototypes ==
353 //===========================================================================================================================
355 //===========================================================================================================================
359 mDNSlocal
void DNSServicesLock( void );
360 mDNSlocal
void DNSServicesUnlock( void );
361 mDNSlocal
void DNSServicesMDNSCallBack( mDNS
*const inMDNS
, mStatus inStatus
);
362 mDNSlocal
void DNSServicesUpdateInterfaceSpecificObjects( mDNS
*const inMDNS
);
367 DNSBrowserPrivateCallBack(
369 DNSQuestion
* inQuestion
,
370 const ResourceRecord
* const inAnswer
,
371 mDNSBool inAddRecord
);
374 DNSBrowserPrivateResolverCallBack(
376 DNSResolverRef inRef
,
377 DNSStatus inStatusCode
,
378 const DNSResolverEvent
* inEvent
);
380 mDNSlocal DNSBrowserRef
DNSBrowserFindObject( DNSBrowserRef inRef
);
381 mDNSlocal DNSBrowserRef
DNSBrowserRemoveObject( DNSBrowserRef inRef
);
385 mDNSlocal
void DNSResolverPrivateCallBack( mDNS
* const inMDNS
, ServiceInfoQuery
*inQuery
);
386 mDNSlocal DNSResolverRef
DNSResolverFindObject( DNSResolverRef inRef
);
387 mDNSlocal DNSResolverRef
DNSResolverRemoveObject( DNSResolverRef inRef
);
388 mDNSlocal
void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef
);
389 mDNSlocal
void DNSResolverRemoveDependentByName( const domainname
*inName
);
390 mDNSlocal DNSResolverRef
DNSResolverFindObjectByName( const domainname
*inName
);
395 DNSRegistrationPrivateCallBack(
397 ServiceRecordSet
* const inSet
,
401 DNSNoSuchServiceRegistrationPrivateCallBack(
403 AuthRecord
* const inRR
,
406 mDNSlocal
void DNSRegistrationUpdateCallBack( mDNS
* const inMDNS
, AuthRecord
* const inRR
, RData
*inOldData
);
408 mDNSlocal DNSRegistrationRef
* DNSRegistrationFindObject( DNSRegistrationRef inRef
);
409 mDNSlocal DNSRegistrationRef
DNSRegistrationRemoveObject( DNSRegistrationRef inRef
);
411 // Domain Registration
413 mDNSlocal DNSDomainRegistrationRef
DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef
);
417 mDNSlocal DNSHostRegistrationRef
* DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef
);
418 mDNSlocal DNSHostRegistrationRef
DNSHostRegistrationFindObjectByName( const domainname
*inName
);
419 mDNSlocal
void DNSHostRegistrationPrivateCallBack( mDNS
* const inMDNS
, AuthRecord
*const inRR
, mStatus inResult
);
423 mDNSlocal DNSStatus
DNSMemAlloc( size_t inSize
, void *outMem
);
424 mDNSlocal
void DNSMemFree( void *inMem
);
425 mDNSlocal
void MDNSAddrToDNSAddress( const mDNSAddr
*inAddr
, mDNSIPPort inPort
, DNSNetworkAddress
*outAddr
);
427 // Platform Accessors
429 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
430 struct mDNSPlatformInterfaceInfo
436 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
437 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
440 #pragma mark == Globals ==
443 //===========================================================================================================================
445 //===========================================================================================================================
447 mDNSexport mDNS gMDNS
;
448 mDNSlocal mDNS
* gMDNSPtr
= mDNSNULL
;
449 mDNSlocal CacheRecord
* gMDNSCache
= mDNSNULL
;
450 mDNSlocal DNSBrowserRef gDNSBrowserList
= mDNSNULL
;
451 mDNSlocal DNSResolverRef gDNSResolverList
= mDNSNULL
;
452 mDNSlocal DNSRegistrationRef gDNSRegistrationList
= mDNSNULL
;
453 mDNSlocal DNSDomainRegistrationRef gDNSDomainRegistrationList
= mDNSNULL
;
454 mDNSlocal DNSHostRegistrationRef gDNSHostRegistrationList
= mDNSNULL
;
458 #pragma mark == General ==
461 //===========================================================================================================================
462 // DNSServicesInitialize
463 //===========================================================================================================================
465 DNSStatus
DNSServicesInitialize( DNSFlags inFlags
, DNSCount inCacheEntryCount
)
470 require_action( ( inFlags
& ~kDNSInitializeValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
472 // Allocate the record cache.
474 if( inCacheEntryCount
== 0 )
476 inCacheEntryCount
= kDNSCountCacheEntryCountDefault
;
478 gMDNSCache
= (CacheRecord
*) malloc( inCacheEntryCount
* sizeof( *gMDNSCache
) );
479 require_action( gMDNSCache
, exit
, err
= kDNSNoMemoryErr
);
483 if( inFlags
& kDNSFlagAdvertise
)
485 advertise
= mDNS_Init_AdvertiseLocalAddresses
;
489 advertise
= mDNS_Init_DontAdvertiseLocalAddresses
;
491 err
= mDNS_Init( &gMDNS
, mDNSNULL
, gMDNSCache
, inCacheEntryCount
, advertise
, DNSServicesMDNSCallBack
, mDNSNULL
);
492 require_noerr( err
, exit
);
493 err
= gMDNS
.mDNSPlatformStatus
;
494 require_noerr( err
, exit
);
501 DNSServicesFinalize();
506 //===========================================================================================================================
507 // DNSServicesFinalize
508 //===========================================================================================================================
510 void DNSServicesFinalize( void )
514 mDNSPlatformLock( &gMDNS
);
516 // Clean up any dangling service registrations.
518 while( gDNSRegistrationList
)
520 DNSRegistrationRef serviceRef
;
522 serviceRef
= gDNSRegistrationList
;
523 DNSRegistrationRelease( serviceRef
, 0UL );
524 check_string( serviceRef
!= gDNSRegistrationList
, "dangling service registration cannot be cleaned up" );
527 // Clean up any dangling domain registrations.
529 while( gDNSDomainRegistrationList
)
531 DNSDomainRegistrationRef domainRef
;
533 domainRef
= gDNSDomainRegistrationList
;
534 DNSDomainRegistrationRelease( domainRef
, 0 );
535 check_string( domainRef
!= gDNSDomainRegistrationList
, "dangling domain registration cannot be cleaned up" );
538 // Clean up any dangling host registrations.
540 while( gDNSHostRegistrationList
)
542 DNSHostRegistrationRef hostRef
;
545 hostRef
= gDNSHostRegistrationList
;
546 refCount
= hostRef
->refCount
;
547 DNSHostRegistrationRelease( hostRef
, 0 );
548 check_string( ( refCount
> 1 ) || ( hostRef
!= gDNSHostRegistrationList
),
549 "dangling host registration cannot be cleaned up" );
552 // Clean up any dangling browsers.
554 while( gDNSBrowserList
)
556 DNSBrowserRef browserRef
;
558 browserRef
= gDNSBrowserList
;
559 DNSBrowserRelease( browserRef
, 0 );
560 check_string( browserRef
!= gDNSBrowserList
, "dangling browser cannot be cleaned up" );
563 // Clean up any dangling resolvers.
565 while( gDNSResolverList
)
567 DNSResolverRef resolverRef
;
569 resolverRef
= gDNSResolverList
;
570 DNSResolverRelease( resolverRef
, 0 );
571 check_string( resolverRef
!= gDNSResolverList
, "dangling resolver cannot be cleaned up" );
574 // Null out our MDNS ptr before releasing the lock so no other threads can sneak in and start operations.
577 mDNSPlatformUnlock( &gMDNS
);
581 mDNS_Close( &gMDNS
);
586 gMDNSCache
= mDNSNULL
;
590 //===========================================================================================================================
592 //===========================================================================================================================
594 mDNSlocal
void DNSServicesLock( void )
598 mDNSPlatformLock( gMDNSPtr
);
602 //===========================================================================================================================
604 //===========================================================================================================================
606 mDNSlocal
void DNSServicesUnlock( void )
610 mDNSPlatformUnlock( gMDNSPtr
);
614 //===========================================================================================================================
615 // DNSServicesMDNSCallBack
616 //===========================================================================================================================
618 mDNSlocal
void DNSServicesMDNSCallBack( mDNS
*const inMDNS
, mStatus inStatus
)
620 DNS_UNUSED( inMDNS
);
621 DNS_UNUSED( inStatus
);
624 debugf( DEBUG_NAME
"MDNS callback (status=%ld)", inStatus
);
626 if( inStatus
== mStatus_ConfigChanged
)
628 DNSServicesUpdateInterfaceSpecificObjects( inMDNS
);
632 //===========================================================================================================================
633 // DNSServicesUpdateInterfaceSpecificObjects
634 //===========================================================================================================================
636 mDNSlocal
void DNSServicesUpdateInterfaceSpecificObjects( mDNS
*const inMDNS
)
638 DNSRegistration
* serviceRegistration
;
642 // Update interface-specific service registrations.
644 for( serviceRegistration
= gDNSRegistrationList
; serviceRegistration
; serviceRegistration
= serviceRegistration
->next
)
646 if( serviceRegistration
->interfaceName
[ 0 ] != '\0' )
649 mDNSInterfaceID interfaceID
;
651 err
= mDNSPlatformInterfaceNameToID( inMDNS
, serviceRegistration
->interfaceName
, &interfaceID
);
653 if( err
== mStatus_NoError
)
655 // Update all the resource records with the new interface ID.
657 serviceRegistration
->set
.RR_ADV
.resrec
.InterfaceID
= interfaceID
;
658 serviceRegistration
->set
.RR_PTR
.resrec
.InterfaceID
= interfaceID
;
659 serviceRegistration
->set
.RR_SRV
.resrec
.InterfaceID
= interfaceID
;
660 serviceRegistration
->set
.RR_TXT
.resrec
.InterfaceID
= interfaceID
;
670 #pragma mark == Browser ==
673 //===========================================================================================================================
675 //===========================================================================================================================
679 DNSBrowserFlags inFlags
,
680 DNSBrowserCallBack inCallBack
,
681 void * inCallBackContext
,
682 DNSBrowserRef
* outRef
)
685 DNSBrowser
* objectPtr
;
688 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
689 require_action( ( inFlags
& ~kDNSBrowserCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
690 require_action( inCallBack
, exit
, err
= kDNSBadParamErr
);
692 // Allocate the object and set it up.
694 err
= DNSMemAlloc( sizeof( *objectPtr
), &objectPtr
);
695 require_noerr( err
, exit
);
696 memset( objectPtr
, 0, sizeof( *objectPtr
) );
698 objectPtr
->flags
= inFlags
;
699 objectPtr
->callback
= inCallBack
;
700 objectPtr
->callbackContext
= inCallBackContext
;
702 // Add the object to the list.
704 objectPtr
->next
= gDNSBrowserList
;
705 gDNSBrowserList
= objectPtr
;
717 //===========================================================================================================================
719 //===========================================================================================================================
721 DNSStatus
DNSBrowserRelease( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
724 DNSBrowserEvent event
;
727 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
728 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
729 require_action( ( inFlags
& ~kDNSBrowserReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
731 // Stop service and domain browsing and remove any resolvers dependent on this browser.
733 DNSBrowserStopDomainSearch( inRef
, 0 );
734 DNSBrowserStopServiceSearch( inRef
, 0 );
735 DNSResolverRemoveDependentByBrowser( inRef
);
737 // Remove the object from the list.
739 inRef
= DNSBrowserRemoveObject( inRef
);
740 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
742 // Call the callback with a release event.
744 check( inRef
->callback
);
745 memset( &event
, 0, sizeof( event
) );
746 event
.type
= kDNSBrowserEventTypeRelease
;
747 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
749 // Release the memory used by the object.
759 //===========================================================================================================================
760 // DNSBrowserStartDomainSearch
761 //===========================================================================================================================
763 DNSStatus
DNSBrowserStartDomainSearch( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
766 mDNS_DomainType type
;
767 mDNS_DomainType defaultType
;
768 DNSBrowserEvent event
;
769 mDNSBool isDomainBrowsing
;
771 isDomainBrowsing
= mDNSfalse
;
774 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
775 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
776 require_action( ( inFlags
& ~kDNSBrowserStartDomainSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
777 require_action( !inRef
->isDomainBrowsing
, exit
, err
= kDNSBadStateErr
);
779 // Determine whether to browse for normal domains or registration domains.
781 if( inFlags
& kDNSBrowserFlagRegistrationDomainsOnly
)
783 type
= mDNS_DomainTypeRegistration
;
784 defaultType
= mDNS_DomainTypeRegistrationDefault
;
788 type
= mDNS_DomainTypeBrowse
;
789 defaultType
= mDNS_DomainTypeBrowseDefault
;
792 // Start the browse operations.
794 err
= mDNS_GetDomains( gMDNSPtr
, &inRef
->domainQuestion
, type
, NULL
, mDNSInterface_Any
, DNSBrowserPrivateCallBack
, inRef
);
795 require_noerr( err
, exit
);
796 isDomainBrowsing
= mDNStrue
;
798 err
= mDNS_GetDomains( gMDNSPtr
, &inRef
->defaultDomainQuestion
, defaultType
, NULL
, mDNSInterface_Any
, DNSBrowserPrivateCallBack
, inRef
);
799 require_noerr( err
, exit
);
801 inRef
->domainSearchFlags
= inFlags
;
802 inRef
->isDomainBrowsing
= mDNStrue
;
804 // Call back immediately with "local." since that is always available for all types of browsing.
806 memset( &event
, 0, sizeof( event
) );
807 event
.type
= kDNSBrowserEventTypeAddDefaultDomain
;
808 event
.data
.addDefaultDomain
.domain
= kDNSLocalDomain
;
809 event
.data
.addDefaultDomain
.flags
= 0;
810 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
813 if( err
&& isDomainBrowsing
)
815 mDNS_StopGetDomains( gMDNSPtr
, &inRef
->domainQuestion
);
821 //===========================================================================================================================
822 // DNSBrowserStopDomainSearch
823 //===========================================================================================================================
825 DNSStatus
DNSBrowserStopDomainSearch( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
830 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
831 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
832 require_action( ( inFlags
& ~kDNSBrowserStopDomainSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
833 if( !inRef
->isDomainBrowsing
)
835 err
= kDNSBadStateErr
;
839 // Stop the browse operations.
841 mDNS_StopGetDomains( gMDNSPtr
, &inRef
->defaultDomainQuestion
);
842 mDNS_StopGetDomains( gMDNSPtr
, &inRef
->domainQuestion
);
843 inRef
->isDomainBrowsing
= mDNSfalse
;
851 //===========================================================================================================================
852 // DNSBrowserStartServiceSearch
853 //===========================================================================================================================
856 DNSBrowserStartServiceSearch(
858 DNSBrowserFlags inFlags
,
860 const char * inDomain
)
867 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
868 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
869 require_action( ( inFlags
& ~kDNSBrowserStartServiceSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
870 require_action( !inRef
->isServiceBrowsing
, exit
, err
= kDNSBadStateErr
);
871 require_action( inType
, exit
, err
= kDNSBadParamErr
);
873 // Default to the local domain when a NULL, empty, or "." domain is passed in.
875 if( !inDomain
|| ( inDomain
[ 0 ] == '\0' ) || ( inDomain
[ 0 ] == '.' ) )
877 inDomain
= kDNSLocalDomain
;
880 // Save off the search criteria (in case it needs to be automatically restarted later).
882 inRef
->serviceSearchFlags
= inFlags
;
884 strncpy( inRef
->searchServiceType
, inType
, sizeof( inRef
->searchServiceType
) - 1 );
885 inRef
->searchServiceType
[ sizeof( inRef
->searchServiceType
) - 1 ] = '\0';
887 strncpy( inRef
->searchDomain
, inDomain
, sizeof( inRef
->searchDomain
) - 1 );
888 inRef
->searchDomain
[ sizeof( inRef
->searchDomain
) - 1 ] = '\0';
890 // Start the browse operation with mDNS using our private callback.
892 MakeDomainNameFromDNSNameString( &type
, inType
);
893 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
895 err
= mDNS_StartBrowse( gMDNSPtr
, &inRef
->serviceBrowseQuestion
, &type
, &domain
, mDNSInterface_Any
, mDNSfalse
,
896 DNSBrowserPrivateCallBack
, inRef
);
897 require_noerr( err
, exit
);
899 inRef
->isServiceBrowsing
= mDNStrue
;
906 //===========================================================================================================================
907 // DNSBrowserStopServiceSearch
908 //===========================================================================================================================
910 DNSStatus
DNSBrowserStopServiceSearch( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
915 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
916 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
917 require_action( ( inFlags
& ~kDNSBrowserStopServiceSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
918 if( !inRef
->isServiceBrowsing
)
920 err
= kDNSBadStateErr
;
924 // Stop the browse operation with mDNS. Remove any resolvers dependent on browser since we are no longer searching.
926 mDNS_StopBrowse( gMDNSPtr
, &inRef
->serviceBrowseQuestion
);
927 DNSResolverRemoveDependentByBrowser( inRef
);
928 inRef
->isServiceBrowsing
= mDNSfalse
;
936 //===========================================================================================================================
937 // DNSBrowserPrivateCallBack
938 //===========================================================================================================================
941 DNSBrowserPrivateCallBack(
943 DNSQuestion
* inQuestion
,
944 const ResourceRecord
* const inAnswer
,
945 mDNSBool inAddRecord
)
947 DNSBrowserRef objectPtr
;
951 char nameString
[ MAX_DOMAIN_LABEL
+ 1 ]; // Name part is not escaped
952 char typeString
[ MAX_ESCAPED_DOMAIN_NAME
];
953 char domainString
[ MAX_ESCAPED_DOMAIN_NAME
];
954 DNSBrowserEvent event
;
963 // Exclude non-PTR answers.
965 require( inAnswer
->rrtype
== kDNSType_PTR
, exit
);
967 // Exit if object is no longer valid. Should never happen.
969 objectPtr
= DNSBrowserFindObject( (DNSBrowserRef
) inQuestion
->QuestionContext
);
970 require( objectPtr
, exit
);
972 // Determine what type of callback it is based on the question.
974 memset( &event
, 0, sizeof( event
) );
975 if( inQuestion
== &objectPtr
->serviceBrowseQuestion
)
977 DNSBrowserEventServiceData
* serviceDataPtr
;
978 DNSBrowserFlags browserFlags
;
980 // Extract name, type, and domain from the resource record.
982 DeconstructServiceName( &inAnswer
->rdata
->u
.name
, &name
, &type
, &domain
);
983 ConvertDomainLabelToCString_unescaped( &name
, nameString
);
984 ConvertDomainNameToCString( &type
, typeString
);
985 ConvertDomainNameToCString( &domain
, domainString
);
987 // Fill in the event data. A TTL of zero means the service is no longer available. If the service instance is going
988 // away (ttl == 0), remove any resolvers dependent on the name since it is no longer valid.
992 DNSResolverRemoveDependentByName( &inAnswer
->rdata
->u
.name
);
994 event
.type
= kDNSBrowserEventTypeRemoveService
;
995 serviceDataPtr
= &event
.data
.removeService
;
999 event
.type
= kDNSBrowserEventTypeAddService
;
1000 serviceDataPtr
= &event
.data
.addService
;
1002 serviceDataPtr
->interfaceName
= "";
1003 if( inAnswer
->InterfaceID
!= mDNSInterface_Any
)
1005 mDNSPlatformInterfaceInfo info
;
1007 err
= mDNSPlatformInterfaceIDToInfo( inMDNS
, inAnswer
->InterfaceID
, &info
);
1008 if( err
== mStatus_NoError
)
1010 serviceDataPtr
->interfaceName
= info
.name
;
1011 MDNSAddrToDNSAddress( &info
.ip
, zeroIPPort
, &serviceDataPtr
->interfaceIP
);
1015 serviceDataPtr
->interfaceName
= "";
1018 serviceDataPtr
->interfaceID
= inAnswer
->InterfaceID
;
1019 serviceDataPtr
->name
= nameString
;
1020 serviceDataPtr
->type
= typeString
;
1021 serviceDataPtr
->domain
= domainString
;
1022 serviceDataPtr
->flags
= 0;
1024 // Call the callback.
1026 browserFlags
= objectPtr
->serviceSearchFlags
;
1027 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1029 // Automatically resolve newly discovered names if the auto-resolve option is enabled.
1031 if( ( browserFlags
& kDNSBrowserFlagAutoResolve
) && inAddRecord
)
1033 DNSResolverFlags flags
;
1035 flags
= kDNSResolverFlagOnlyIfUnique
| kDNSResolverFlagAutoReleaseByName
;
1036 err
= DNSResolverCreate( flags
, nameString
, typeString
, domainString
, DNSBrowserPrivateResolverCallBack
,
1037 mDNSNULL
, objectPtr
, mDNSNULL
);
1043 DNSBrowserEventDomainData
* domainDataPtr
;
1045 // Determine the event type. A TTL of zero means the domain is no longer available.
1047 domainDataPtr
= mDNSNULL
;
1048 if( inQuestion
== &objectPtr
->domainQuestion
)
1052 event
.type
= kDNSBrowserEventTypeRemoveDomain
;
1053 domainDataPtr
= &event
.data
.removeDomain
;
1057 event
.type
= kDNSBrowserEventTypeAddDomain
;
1058 domainDataPtr
= &event
.data
.addDomain
;
1061 else if( inQuestion
== &objectPtr
->defaultDomainQuestion
)
1065 event
.type
= kDNSBrowserEventTypeRemoveDomain
;
1066 domainDataPtr
= &event
.data
.removeDomain
;
1070 event
.type
= kDNSBrowserEventTypeAddDefaultDomain
;
1071 domainDataPtr
= &event
.data
.addDefaultDomain
;
1074 require_string( domainDataPtr
, exit
, "domain response for unknown question" );
1076 // Extract domain name from the resource record and fill in the event data.
1078 ConvertDomainNameToCString( &inAnswer
->rdata
->u
.name
, domainString
);
1080 domainDataPtr
->interfaceName
= "";
1081 if( inAnswer
->InterfaceID
!= mDNSInterface_Any
)
1083 mDNSPlatformInterfaceInfo info
;
1085 err
= mDNSPlatformInterfaceIDToInfo( inMDNS
, inAnswer
->InterfaceID
, &info
);
1086 if( err
== mStatus_NoError
)
1088 domainDataPtr
->interfaceName
= info
.name
;
1089 MDNSAddrToDNSAddress( &info
.ip
, zeroIPPort
, &domainDataPtr
->interfaceIP
);
1093 domainDataPtr
->interfaceName
= "";
1096 domainDataPtr
->interfaceID
= inAnswer
->InterfaceID
;
1097 domainDataPtr
->domain
= domainString
;
1098 domainDataPtr
->flags
= 0;
1100 // Call the callback.
1102 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1106 DNSServicesUnlock();
1109 //===========================================================================================================================
1110 // DNSBrowserPrivateResolverCallBack
1111 //===========================================================================================================================
1114 DNSBrowserPrivateResolverCallBack(
1116 DNSResolverRef inRef
,
1117 DNSStatus inStatusCode
,
1118 const DNSResolverEvent
* inEvent
)
1120 DNSBrowserRef objectPtr
;
1121 DNSBrowserEvent event
;
1123 DNS_UNUSED( inContext
);
1124 DNS_UNUSED( inStatusCode
);
1128 // Exit if object is no longer valid. Should never happen.
1130 objectPtr
= inRef
->owner
;
1131 require( objectPtr
, exit
);
1133 switch( inEvent
->type
)
1135 case kDNSResolverEventTypeResolved
:
1137 // Re-package the resolver event as a browser event and call the callback.
1139 memset( &event
, 0, sizeof( event
) );
1140 event
.type
= kDNSBrowserEventTypeResolved
;
1141 event
.data
.resolved
= &inEvent
->data
.resolved
;
1143 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1146 case kDNSResolverEventTypeRelease
:
1147 verbosedebugf( DEBUG_NAME
"private resolver callback: release (ref=0x%p)", inRef
);
1151 verbosedebugf( DEBUG_NAME
"private resolver callback: unknown event (ref=0x%p, event=%ld)", inRef
, inEvent
->type
);
1156 DNSServicesUnlock();
1159 //===========================================================================================================================
1160 // DNSBrowserFindObject
1162 // Warning: Assumes the DNS lock is held.
1163 //===========================================================================================================================
1165 mDNSlocal DNSBrowserRef
DNSBrowserFindObject( DNSBrowserRef inRef
)
1171 // Find the object in the list.
1173 for( p
= gDNSBrowserList
; p
; p
= p
->next
)
1183 //===========================================================================================================================
1184 // DNSBrowserRemoveObject
1186 // Warning: Assumes the DNS lock is held.
1187 //===========================================================================================================================
1189 mDNSlocal DNSBrowserRef
DNSBrowserRemoveObject( DNSBrowserRef inRef
)
1194 for( p
= &gDNSBrowserList
; *p
; p
= &( *p
)->next
)
1211 #pragma mark == Resolver ==
1214 //===========================================================================================================================
1215 // DNSResolverCreate
1216 //===========================================================================================================================
1220 DNSResolverFlags inFlags
,
1221 const char * inName
,
1222 const char * inType
,
1223 const char * inDomain
,
1224 DNSResolverCallBack inCallBack
,
1225 void * inCallBackContext
,
1226 DNSBrowserRef inOwner
,
1227 DNSResolverRef
* outRef
)
1231 DNSResolver
* objectPtr
;
1235 domainname fullName
;
1237 objectPtr
= mDNSNULL
;
1239 // Check parameters.
1242 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1243 require_action( ( inFlags
& ~kDNSResolverCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1244 require_action( inName
, exit
, err
= kDNSBadParamErr
);
1245 require_action( inType
, exit
, err
= kDNSBadParamErr
);
1246 require_action( inDomain
, exit
, err
= kDNSBadParamErr
);
1247 require_action( inCallBack
, exit
, err
= kDNSBadParamErr
);
1248 isAutoRelease
= inOwner
|| ( inFlags
& ( kDNSResolverFlagOneShot
| kDNSResolverFlagAutoReleaseByName
) );
1249 require_action( outRef
|| isAutoRelease
, exit
, err
= kDNSBadParamErr
);
1250 require_action( !inOwner
|| DNSBrowserFindObject( inOwner
), exit
, err
= kDNSBadReferenceErr
);
1252 // Convert and package up the name, type, and domain into a single fully-qualified domain name to resolve.
1254 MakeDomainLabelFromLiteralString( &name
, inName
);
1255 MakeDomainNameFromDNSNameString( &type
, inType
);
1256 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
1257 ConstructServiceName( &fullName
, &name
, &type
, &domain
);
1259 // If the caller only wants to add unique resolvers, check if a resolver for this name is already present.
1261 if( inFlags
& kDNSResolverFlagOnlyIfUnique
)
1263 if( DNSResolverFindObjectByName( &fullName
) )
1274 // Allocate the object and set it up.
1276 err
= DNSMemAlloc( sizeof( *objectPtr
), &objectPtr
);
1277 require_noerr( err
, exit
);
1278 memset( objectPtr
, 0, sizeof( *objectPtr
) );
1280 objectPtr
->flags
= inFlags
;
1281 objectPtr
->callback
= inCallBack
;
1282 objectPtr
->callbackContext
= inCallBackContext
;
1283 objectPtr
->owner
= inOwner
;
1284 AssignDomainName( &objectPtr
->info
.name
, &fullName
);
1285 objectPtr
->info
.InterfaceID
= mDNSInterface_Any
;
1287 // Save off the resolve info so the callback can get it.
1289 strncpy( objectPtr
->resolveName
, inName
, sizeof( objectPtr
->resolveName
) - 1 );
1290 objectPtr
->resolveName
[ sizeof( objectPtr
->resolveName
) - 1 ] = '\0';
1292 strncpy( objectPtr
->resolveType
, inType
, sizeof( objectPtr
->resolveType
) - 1 );
1293 objectPtr
->resolveType
[ sizeof( objectPtr
->resolveType
) - 1 ] = '\0';
1295 strncpy( objectPtr
->resolveDomain
, inDomain
, sizeof( objectPtr
->resolveDomain
) - 1 );
1296 objectPtr
->resolveDomain
[ sizeof( objectPtr
->resolveDomain
) - 1 ] = '\0';
1298 // Add the object to the list.
1300 objectPtr
->next
= gDNSResolverList
;
1301 gDNSResolverList
= objectPtr
;
1303 // Start the resolving process.
1305 objectPtr
->isResolving
= mDNStrue
;
1306 err
= mDNS_StartResolveService( gMDNSPtr
, &objectPtr
->query
, &objectPtr
->info
, DNSResolverPrivateCallBack
, objectPtr
);
1307 require_noerr( err
, exit
);
1311 *outRef
= objectPtr
;
1315 if( err
&& objectPtr
)
1317 DNSResolverRemoveObject( objectPtr
);
1318 DNSMemFree( objectPtr
);
1320 DNSServicesUnlock();
1324 //===========================================================================================================================
1325 // DNSResolverRelease
1326 //===========================================================================================================================
1328 DNSStatus
DNSResolverRelease( DNSResolverRef inRef
, DNSResolverFlags inFlags
)
1331 DNSResolverEvent event
;
1334 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1335 require_action( ( inFlags
& ~kDNSResolverReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1337 // Remove the object from the list.
1339 inRef
= DNSResolverRemoveObject( inRef
);
1340 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
1342 // Stop the resolving process.
1344 if( inRef
->isResolving
)
1346 inRef
->isResolving
= mDNSfalse
;
1347 mDNS_StopResolveService( gMDNSPtr
, &inRef
->query
);
1350 // Call the callback with a release event.
1352 check( inRef
->callback
);
1353 memset( &event
, 0, sizeof( event
) );
1354 event
.type
= kDNSResolverEventTypeRelease
;
1355 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
1357 // Release the memory used by the object.
1359 DNSMemFree( inRef
);
1363 DNSServicesUnlock();
1367 //===========================================================================================================================
1368 // DNSResolverFindObject
1370 // Warning: Assumes the DNS lock is held.
1371 //===========================================================================================================================
1373 mDNSlocal DNSResolverRef
DNSResolverFindObject( DNSResolverRef inRef
)
1379 // Find the object in the list.
1381 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1391 //===========================================================================================================================
1392 // DNSResolverFindObjectByName
1394 // Warning: Assumes the DNS lock is held.
1395 //===========================================================================================================================
1397 mDNSlocal DNSResolverRef
DNSResolverFindObjectByName( const domainname
*inName
)
1403 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1405 if( SameDomainName( &p
->info
.name
, inName
) )
1413 //===========================================================================================================================
1414 // DNSResolverPrivateCallBack
1415 //===========================================================================================================================
1417 mDNSlocal
void DNSResolverPrivateCallBack( mDNS
* const inMDNS
, ServiceInfoQuery
*inQuery
)
1419 DNSResolverRef objectPtr
;
1420 DNSResolverEvent event
;
1424 char hostName
[ MAX_ESCAPED_DOMAIN_NAME
];
1430 // Exit if object is no longer valid. Should never happen.
1432 objectPtr
= DNSResolverFindObject( (DNSResolverRef
) inQuery
->ServiceInfoQueryContext
);
1433 require( objectPtr
, exit
);
1435 // Convert the raw TXT record into a null-terminated string with \001-delimited records for Mac OS X-style clients.
1437 err
= DNSTextRecordEscape( inQuery
->info
->TXTinfo
, inQuery
->info
->TXTlen
, &txtString
);
1440 // Package up the results and call the callback.
1442 memset( &event
, 0, sizeof( event
) );
1443 event
.type
= kDNSResolverEventTypeResolved
;
1444 event
.data
.resolved
.name
= objectPtr
->resolveName
;
1445 event
.data
.resolved
.type
= objectPtr
->resolveType
;
1446 event
.data
.resolved
.domain
= objectPtr
->resolveDomain
;
1447 event
.data
.resolved
.interfaceName
= "";
1448 if( inQuery
->info
->InterfaceID
!= mDNSInterface_Any
)
1450 mDNSPlatformInterfaceInfo info
;
1452 err
= mDNSPlatformInterfaceIDToInfo( inMDNS
, inQuery
->info
->InterfaceID
, &info
);
1453 if( err
== mStatus_NoError
)
1455 event
.data
.resolved
.interfaceName
= info
.name
;
1456 MDNSAddrToDNSAddress( &info
.ip
, zeroIPPort
, &event
.data
.resolved
.interfaceIP
);
1460 event
.data
.resolved
.interfaceName
= "";
1463 event
.data
.resolved
.interfaceID
= inQuery
->info
->InterfaceID
;
1464 MDNSAddrToDNSAddress( &inQuery
->info
->ip
, inQuery
->info
->port
, &event
.data
.resolved
.address
);
1465 event
.data
.resolved
.textRecord
= txtString
? txtString
: "";
1466 event
.data
.resolved
.flags
= 0;
1467 event
.data
.resolved
.textRecordRaw
= (const void *) inQuery
->info
->TXTinfo
;
1468 event
.data
.resolved
.textRecordRawSize
= (DNSCount
) inQuery
->info
->TXTlen
;
1469 ConvertDomainNameToCString( &inQuery
->qAv4
.qname
, hostName
);
1470 event
.data
.resolved
.hostName
= hostName
;
1471 release
= (mDNSBool
)( ( objectPtr
->flags
& kDNSResolverFlagOneShot
) != 0 );
1472 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1474 // Auto-release the object if needed.
1478 DNSResolverRelease( objectPtr
, 0 );
1482 DNSServicesUnlock();
1489 //===========================================================================================================================
1490 // DNSResolverRemoveObject
1492 // Warning: Assumes the DNS lock is held.
1493 //===========================================================================================================================
1495 mDNSlocal DNSResolverRef
DNSResolverRemoveObject( DNSResolverRef inRef
)
1498 DNSResolver
* found
;
1500 for( p
= &gDNSResolverList
; *p
; p
= &( *p
)->next
)
1515 //===========================================================================================================================
1516 // DNSResolverRemoveDependentByBrowser
1518 // Warning: Assumes the DNS lock is held.
1519 //===========================================================================================================================
1521 mDNSlocal
void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef
)
1525 check( inBrowserRef
);
1527 // Removes all the resolver objects dependent on the specified browser. Restart the search from the beginning of the
1528 // list after each removal to handle the list changing in possible callbacks that may be invoked.
1532 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1534 if( p
->owner
== inBrowserRef
)
1536 DNSResolverRelease( p
, 0 );
1544 //===========================================================================================================================
1545 // DNSResolverRemoveDependentByName
1547 // Warning: Assumes the DNS lock is held.
1548 //===========================================================================================================================
1550 mDNSlocal
void DNSResolverRemoveDependentByName( const domainname
*inName
)
1556 // Removes all the resolver objects dependent on the specified name that want to be auto-released by name. Restart
1557 // the search from the beginning of the list after each removal to handle the list changing in possible callbacks
1558 // that may be invoked.
1562 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1564 if( ( p
->flags
& kDNSResolverFlagAutoReleaseByName
) && SameDomainName( &p
->info
.name
, inName
) )
1566 DNSResolverRelease( p
, 0 );
1576 #pragma mark == Registration ==
1579 //===========================================================================================================================
1580 // DNSRegistrationCreate
1581 //===========================================================================================================================
1584 DNSRegistrationCreate(
1585 DNSRegistrationFlags inFlags
,
1586 const char * inName
,
1587 const char * inType
,
1588 const char * inDomain
,
1590 const void * inTextRecord
,
1591 DNSCount inTextRecordSize
,
1592 const char * inHost
,
1593 const char * inInterfaceName
,
1594 DNSRegistrationCallBack inCallBack
,
1595 void * inCallBackContext
,
1596 DNSRegistrationRef
* outRef
)
1600 DNSRegistration
* objectPtr
;
1601 mDNSInterfaceID interfaceID
;
1605 mDNSu8 textRecord
[ 256 ];
1606 const mDNSu8
* textRecordPtr
;
1608 domainname tempHost
;
1610 objectPtr
= mDNSNULL
;
1612 // Check parameters.
1615 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1616 require_action( ( inFlags
& ~kDNSRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1617 require_action( inType
, exit
, err
= kDNSBadParamErr
);
1618 require_action( inTextRecord
|| ( inTextRecordSize
== 0 ), exit
, err
= kDNSBadParamErr
);
1619 require_action( ( inFlags
& kDNSRegistrationFlagPreFormattedTextRecord
) ||
1620 ( inTextRecordSize
< sizeof( textRecord
) ), exit
, err
= kDNSBadParamErr
);
1621 require_action( !inInterfaceName
||
1622 ( strlen( inInterfaceName
) < sizeof( objectPtr
->interfaceName
) ), exit
, err
= kDNSBadParamErr
);
1624 // Default to the local domain when a NULL, empty, or "." domain is passed in.
1626 if( !inDomain
|| ( inDomain
[ 0 ] == '\0' ) || ( inDomain
[ 0 ] == '.' ) )
1628 inDomain
= kDNSLocalDomain
;
1631 // Set up the text record. If the pre-formatted flag is used, the input text is assumed to be a valid text record
1632 // and is used directly. Otherwise, the input text is assumed to be raw text and is converted to a text record.
1634 textRecordPtr
= (const mDNSu8
*) inTextRecord
;
1635 if( !( inFlags
& kDNSRegistrationFlagPreFormattedTextRecord
) )
1637 // Convert the raw input text to a length-prefixed text record.
1639 if( inTextRecordSize
> 0 )
1641 textRecord
[ 0 ] = (mDNSu8
) inTextRecordSize
;
1642 memcpy( &textRecord
[ 1 ], inTextRecord
, inTextRecordSize
);
1643 textRecordPtr
= textRecord
;
1644 inTextRecordSize
+= 1;
1648 // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
1650 size
= sizeof( *objectPtr
);
1651 if( inTextRecordSize
> sizeof( RDataBody
) )
1653 size
+= ( inTextRecordSize
- sizeof( RDataBody
) );
1656 err
= DNSMemAlloc( size
, &objectPtr
);
1657 require_noerr( err
, exit
);
1658 memset( objectPtr
, 0, size
);
1660 objectPtr
->flags
= inFlags
;
1661 objectPtr
->callback
= inCallBack
;
1662 objectPtr
->callbackContext
= inCallBackContext
;
1664 // Set up the interface for interface-specific operations.
1666 if( inInterfaceName
&& ( *inInterfaceName
!= '\0' ) )
1668 strcpy( objectPtr
->interfaceName
, inInterfaceName
);
1670 err
= mDNSPlatformInterfaceNameToID( gMDNSPtr
, inInterfaceName
, &interfaceID
);
1671 require_noerr( err
, exit
);
1675 interfaceID
= mDNSInterface_Any
;
1678 // Add the object to the list.
1680 objectPtr
->next
= gDNSRegistrationList
;
1681 gDNSRegistrationList
= objectPtr
;
1683 // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string,
1684 // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
1685 // If we're using the system name (i.e. name is NULL), automatically rename on conflicts to keep things in sync.
1687 if( !inName
|| ( *inName
== '\0' ) )
1689 name
= gMDNSPtr
->nicelabel
;
1690 inFlags
|= kDNSRegistrationFlagAutoRenameOnConflict
;
1694 MakeDomainLabelFromLiteralString( &name
, inName
);
1696 MakeDomainNameFromDNSNameString( &type
, inType
);
1697 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
1699 // Set up the host name (if not using the default).
1705 MakeDomainNameFromDNSNameString( host
, inHost
);
1706 AppendDomainName( host
, &domain
);
1709 // Register the service with mDNS.
1711 err
= mDNS_RegisterService( gMDNSPtr
, &objectPtr
->set
, &name
, &type
, &domain
, host
, mDNSOpaque16fromIntVal(inPort
), textRecordPtr
,
1712 (mDNSu16
) inTextRecordSize
, NULL
, 0, interfaceID
,
1713 DNSRegistrationPrivateCallBack
, objectPtr
);
1714 require_noerr( err
, exit
);
1718 *outRef
= objectPtr
;
1722 if( err
&& objectPtr
)
1724 DNSRegistrationRemoveObject( objectPtr
);
1725 DNSMemFree( objectPtr
);
1727 DNSServicesUnlock();
1731 //===========================================================================================================================
1732 // DNSNoSuchServiceRegistrationCreate
1733 //===========================================================================================================================
1736 DNSNoSuchServiceRegistrationCreate(
1737 DNSRegistrationFlags inFlags
,
1738 const char * inName
,
1739 const char * inType
,
1740 const char * inDomain
,
1741 const char * inInterfaceName
,
1742 DNSRegistrationCallBack inCallBack
,
1743 void * inCallBackContext
,
1744 DNSRegistrationRef
* outRef
)
1748 DNSRegistration
* objectPtr
;
1749 mDNSInterfaceID interfaceID
;
1754 objectPtr
= mDNSNULL
;
1756 // Check parameters.
1759 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1760 require_action( ( inFlags
& ~kDNSNoSuchServiceRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1761 inFlags
|= kDNSRegistrationFlagPrivateNoSuchService
;
1762 require_action( inType
, exit
, err
= kDNSBadParamErr
);
1763 require_action( !inInterfaceName
||
1764 ( strlen( inInterfaceName
) < sizeof( objectPtr
->interfaceName
) ), exit
, err
= kDNSBadParamErr
);
1766 // Default to the local domain when a NULL, empty, or "." domain is passed in.
1768 if( !inDomain
|| ( inDomain
[ 0 ] == '\0' ) || ( inDomain
[ 0 ] == '.' ) )
1770 inDomain
= kDNSLocalDomain
;
1773 // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
1775 size
= sizeof( *objectPtr
);
1777 err
= DNSMemAlloc( size
, &objectPtr
);
1778 require_noerr( err
, exit
);
1779 memset( objectPtr
, 0, size
);
1781 objectPtr
->flags
= inFlags
;
1782 objectPtr
->callback
= inCallBack
;
1783 objectPtr
->callbackContext
= inCallBackContext
;
1785 // Set up the interface for interface-specific operations.
1787 if( inInterfaceName
&& ( *inInterfaceName
!= '\0' ) )
1789 strcpy( objectPtr
->interfaceName
, inInterfaceName
);
1791 err
= mDNSPlatformInterfaceNameToID( gMDNSPtr
, inInterfaceName
, &interfaceID
);
1792 require_noerr( err
, exit
);
1796 interfaceID
= mDNSInterface_Any
;
1799 // Add the object to the list.
1801 objectPtr
->next
= gDNSRegistrationList
;
1802 gDNSRegistrationList
= objectPtr
;
1804 // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string,
1805 // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
1807 if( !inName
|| ( *inName
== '\0' ) )
1809 name
= gMDNSPtr
->nicelabel
;
1813 MakeDomainLabelFromLiteralString( &name
, inName
);
1815 MakeDomainNameFromDNSNameString( &type
, inType
);
1816 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
1818 // Register the service with mDNS.
1820 err
= mDNS_RegisterNoSuchService( gMDNSPtr
, &objectPtr
->set
.RR_SRV
, &name
, &type
, &domain
, mDNSNULL
,
1821 interfaceID
, DNSNoSuchServiceRegistrationPrivateCallBack
, objectPtr
);
1822 require_noerr( err
, exit
);
1826 *outRef
= objectPtr
;
1830 if( err
&& objectPtr
)
1832 DNSRegistrationRemoveObject( objectPtr
);
1833 DNSMemFree( objectPtr
);
1835 DNSServicesUnlock();
1839 //===========================================================================================================================
1840 // DNSRegistrationRelease
1841 //===========================================================================================================================
1843 DNSStatus
DNSRegistrationRelease( DNSRegistrationRef inRef
, DNSRegistrationFlags inFlags
)
1846 DNSRegistrationEvent event
;
1849 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1850 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
1851 require_action( ( inFlags
& ~kDNSRegistrationReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1853 // Notify the client of the registration release. Remove the object first so they cannot try to use it in the callback.
1855 inRef
= DNSRegistrationRemoveObject( inRef
);
1856 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
1858 if( inRef
->callback
)
1860 memset( &event
, 0, sizeof( event
) );
1861 event
.type
= kDNSRegistrationEventTypeRelease
;
1862 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
1865 // Deregister from mDNS after everything else since it will call us back to free the memory.
1867 if( !( inRef
->flags
& kDNSRegistrationFlagPrivateNoSuchService
) )
1869 err
= mDNS_DeregisterService( gMDNSPtr
, &inRef
->set
);
1870 require_noerr( err
, exit
);
1874 err
= mDNS_DeregisterNoSuchService( gMDNSPtr
, &inRef
->set
.RR_SRV
);
1875 require_noerr( err
, exit
);
1878 // Note: Don't free here. Wait for mDNS to call us back with a mem free result.
1881 DNSServicesUnlock();
1885 //===========================================================================================================================
1886 // DNSRegistrationUpdate
1887 //===========================================================================================================================
1890 DNSRegistrationUpdate(
1891 DNSRegistrationRef inRef
,
1892 DNSRecordFlags inFlags
,
1893 DNSRegistrationRecordRef inRecord
,
1894 const void * inData
,
1896 DNSUInt32 inNewTTL
)
1903 newRData
= mDNSNULL
;
1906 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1907 require_action( DNSRegistrationFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
1908 require_action( ( inFlags
& ~kDNSRegistrationUpdateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1909 require_action( inData
|| ( inSize
== 0 ), exit
, err
= kDNSBadParamErr
);
1911 // If a non-NULL record is specified, update it. Otherwise, use the standard TXT record.
1915 // $$$ TO DO: Add support for updating extra records (support adding and removing them too).
1918 err
= kDNSUnsupportedErr
;
1919 require_noerr( err
, exit
);
1923 rr
= &inRef
->set
.RR_TXT
;
1926 // Allocate storage for the new data and set it up.
1928 maxRDLength
= sizeof( RDataBody
);
1929 if( inSize
> maxRDLength
)
1931 maxRDLength
= inSize
;
1933 err
= DNSMemAlloc( ( sizeof( *newRData
) - sizeof( RDataBody
) ) + maxRDLength
, &newRData
);
1934 require_noerr( err
, exit
);
1936 newRData
->MaxRDLength
= (mDNSu16
) maxRDLength
;
1937 memcpy( &newRData
->u
, inData
, inSize
);
1939 // Update the record with mDNS.
1941 err
= mDNS_Update( gMDNSPtr
, rr
, inNewTTL
, (mDNSu16
) inSize
, newRData
, DNSRegistrationUpdateCallBack
);
1942 require_noerr( err
, exit
);
1944 newRData
= mDNSNULL
;
1949 DNSMemFree( newRData
);
1951 DNSServicesUnlock();
1955 //===========================================================================================================================
1956 // DNSRegistrationPrivateCallBack
1957 //===========================================================================================================================
1959 mDNSlocal
void DNSRegistrationPrivateCallBack( mDNS
* const inMDNS
, ServiceRecordSet
* const inSet
, mStatus inResult
)
1961 DNSRegistrationRef object
;
1962 DNSRegistrationEvent event
;
1964 DNS_UNUSED( inMDNS
);
1968 // Exit if object is no longer valid. Should never happen.
1970 object
= (DNSRegistrationRef
) inSet
->ServiceContext
;
1971 require( object
, exit
);
1973 // Dispatch based on the status code.
1977 case mStatus_NoError
:
1978 debugf( DEBUG_NAME
"registration callback: \"%##s\" name successfully registered", inSet
->RR_SRV
.resrec
.name
.c
);
1980 // Notify the client of a successful registration.
1982 if( object
->callback
)
1984 memset( &event
, 0, sizeof( event
) );
1985 event
.type
= kDNSRegistrationEventTypeRegistered
;
1986 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
1990 case mStatus_NameConflict
:
1995 debugf( DEBUG_NAME
"registration callback: \"%##s\" name conflict", inSet
->RR_SRV
.resrec
.name
.c
);
1997 // Name conflict. If the auto-rename option is enabled, uniquely rename the service and re-register it. Otherwise,
1998 // remove the object so they cannot try to use it in the callback and notify the client of the name conflict.
2000 removeIt
= mDNStrue
;
2001 if( object
->flags
& kDNSRegistrationFlagAutoRenameOnConflict
)
2003 err
= mDNS_RenameAndReregisterService( inMDNS
, inSet
, mDNSNULL
);
2005 if( err
== mStatus_NoError
)
2007 debugf( DEBUG_NAME
"registration callback: auto-renamed to \"%##s\"", inSet
->RR_SRV
.resrec
.name
.c
);
2008 removeIt
= mDNSfalse
;
2013 object
= DNSRegistrationRemoveObject( object
);
2014 require( object
, exit
);
2016 // Notify the client of the name collision.
2018 if( object
->callback
)
2020 memset( &event
, 0, sizeof( event
) );
2021 event
.type
= kDNSRegistrationEventTypeNameCollision
;
2022 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2025 // Notify the client that the registration is being released.
2027 if( object
->callback
)
2029 memset( &event
, 0, sizeof( event
) );
2030 event
.type
= kDNSRegistrationEventTypeRelease
;
2031 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2034 // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
2036 DNSMemFree( object
);
2041 case mStatus_MemFree
:
2042 debugf( DEBUG_NAME
"registration callback: \"%##s\" memory free", inSet
->RR_SRV
.resrec
.name
.c
);
2044 if( object
->set
.RR_TXT
.resrec
.rdata
!= &object
->set
.RR_TXT
.rdatastorage
)
2046 // Standard TXT record was updated with new data so free that data separately.
2048 DNSMemFree( object
->set
.RR_TXT
.resrec
.rdata
);
2050 DNSMemFree( object
);
2054 debugf( DEBUG_NAME
"registration callback: \"%##s\" unknown result %d", inSet
->RR_SRV
.resrec
.name
.c
, inResult
);
2059 DNSServicesUnlock();
2062 //===========================================================================================================================
2063 // DNSNoSuchServiceRegistrationPrivateCallBack
2064 //===========================================================================================================================
2066 mDNSlocal
void DNSNoSuchServiceRegistrationPrivateCallBack( mDNS
* const inMDNS
, AuthRecord
* const inRR
, mStatus inResult
)
2068 DNSRegistrationRef object
;
2069 DNSRegistrationEvent event
;
2071 DNS_UNUSED( inMDNS
);
2075 // Exit if object is no longer valid. Should never happen.
2077 object
= (DNSRegistrationRef
) inRR
->RecordContext
;
2078 require( object
, exit
);
2080 // Dispatch based on the status code.
2084 case mStatus_NoError
:
2085 debugf( DEBUG_NAME
"registration callback: \"%##s\" name successfully registered", inRR
->resrec
.name
.c
);
2087 // Notify the client of a successful registration.
2089 if( object
->callback
)
2091 memset( &event
, 0, sizeof( event
) );
2092 event
.type
= kDNSRegistrationEventTypeRegistered
;
2093 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2097 case mStatus_NameConflict
:
2099 debugf( DEBUG_NAME
"registration callback: \"%##s\" name conflict", inRR
->resrec
.name
.c
);
2101 // Name conflict. Name conflicts for no-such-service registrations often do not make sense since the main goal
2102 // is to assert that no other service exists with a name. Because of this, name conflicts should be handled by
2103 // the code registering the no-such-service since it is likely that if another service is already using the
2104 // name that the service registering the no-such-service should rename its other services as well. The name
2105 // collision client callback invoked here can do any of this client-specific behavior. It may be worth adding
2106 // support for the auto-rename feature in the future though, if that becomes necessary.
2108 object
= DNSRegistrationRemoveObject( object
);
2109 require( object
, exit
);
2111 // Notify the client of the name collision.
2113 if( object
->callback
)
2115 memset( &event
, 0, sizeof( event
) );
2116 event
.type
= kDNSRegistrationEventTypeNameCollision
;
2117 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2120 // Notify the client that the registration is being released.
2122 if( object
->callback
)
2124 memset( &event
, 0, sizeof( event
) );
2125 event
.type
= kDNSRegistrationEventTypeRelease
;
2126 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2129 // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
2131 DNSMemFree( object
);
2135 case mStatus_MemFree
:
2136 debugf( DEBUG_NAME
"registration callback: \"%##s\" memory free", inRR
->resrec
.name
.c
);
2138 DNSMemFree( object
);
2142 debugf( DEBUG_NAME
"registration callback: \"%##s\" unknown result %d", inRR
->resrec
.name
.c
, inResult
);
2147 DNSServicesUnlock();
2150 //===========================================================================================================================
2151 // DNSRegistrationUpdateCallBack
2152 //===========================================================================================================================
2154 mDNSlocal
void DNSRegistrationUpdateCallBack( mDNS
* const inMDNS
, AuthRecord
* const inRR
, RData
*inOldData
)
2156 DNS_UNUSED( inMDNS
);
2161 if( inOldData
!= &inRR
->rdatastorage
)
2163 DNSMemFree( inOldData
);
2167 //===========================================================================================================================
2168 // DNSRegistrationFindObject
2170 // Warning: Assumes the DNS lock is held.
2171 //===========================================================================================================================
2173 mDNSlocal DNSRegistrationRef
* DNSRegistrationFindObject( DNSRegistrationRef inRef
)
2175 DNSRegistration
** p
;
2177 for( p
= &gDNSRegistrationList
; *p
; p
= &( *p
)->next
)
2187 //===========================================================================================================================
2188 // DNSRegistrationRemoveObject
2190 // Warning: Assumes the DNS lock is held.
2191 //===========================================================================================================================
2193 mDNSlocal DNSRegistrationRef
DNSRegistrationRemoveObject( DNSRegistrationRef inRef
)
2195 DNSRegistration
** p
;
2196 DNSRegistration
* found
;
2198 for( p
= &gDNSRegistrationList
; *p
; p
= &( *p
)->next
)
2215 #pragma mark == Domain Registration ==
2218 //===========================================================================================================================
2219 // DNSDomainRegistrationCreate
2220 //===========================================================================================================================
2223 DNSDomainRegistrationCreate(
2224 DNSDomainRegistrationFlags inFlags
,
2225 const char * inName
,
2226 DNSDomainRegistrationType inType
,
2227 DNSDomainRegistrationRef
* outRef
)
2230 DNSDomainRegistration
* objectPtr
;
2232 objectPtr
= mDNSNULL
;
2234 // Check parameters.
2237 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2238 require_action( ( inFlags
& ~kDNSDomainRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2239 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2240 require_action( inType
< kDNSDomainRegistrationTypeMax
, exit
, err
= kDNSBadParamErr
);
2242 // Allocate the object and set it up.
2244 err
= DNSMemAlloc( sizeof( *objectPtr
), &objectPtr
);
2245 require_noerr( err
, exit
);
2246 memset( objectPtr
, 0, sizeof( *objectPtr
) );
2248 objectPtr
->flags
= inFlags
;
2250 // Add the object to the list.
2252 objectPtr
->next
= gDNSDomainRegistrationList
;
2253 gDNSDomainRegistrationList
= objectPtr
;
2255 // Register the domain with mDNS.
2257 err
= mDNS_AdvertiseDomains( gMDNSPtr
, &objectPtr
->rr
, (mDNS_DomainType
) inType
, mDNSInterface_Any
, (char *) inName
);
2258 require_noerr( err
, exit
);
2262 *outRef
= objectPtr
;
2266 if( err
&& objectPtr
)
2268 DNSDomainRegistrationRemoveObject( objectPtr
);
2269 DNSMemFree( objectPtr
);
2271 DNSServicesUnlock();
2275 //===========================================================================================================================
2276 // DNSDomainRegistrationRelease
2277 //===========================================================================================================================
2279 DNSStatus
DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef
, DNSDomainRegistrationFlags inFlags
)
2284 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2285 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2286 require_action( ( inFlags
& ~kDNSDomainRegistrationReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2288 // Remove the object and deregister the domain with mDNS.
2290 inRef
= DNSDomainRegistrationRemoveObject( inRef
);
2291 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2293 mDNS_StopAdvertiseDomains( gMDNSPtr
, &inRef
->rr
);
2295 // Release the memory used by the object.
2297 DNSMemFree( inRef
);
2301 DNSServicesUnlock();
2305 //===========================================================================================================================
2306 // DNSDomainRegistrationRemoveObject
2308 // Warning: Assumes the DNS lock is held.
2309 //===========================================================================================================================
2311 mDNSlocal DNSDomainRegistrationRef
DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef
)
2313 DNSDomainRegistration
** p
;
2314 DNSDomainRegistration
* found
;
2316 for( p
= &gDNSDomainRegistrationList
; *p
; p
= &( *p
)->next
)
2333 #pragma mark == Domain Registration ==
2336 //===========================================================================================================================
2337 // DNSHostRegistrationCreate
2338 //===========================================================================================================================
2341 DNSHostRegistrationCreate(
2342 DNSHostRegistrationFlags inFlags
,
2343 const char * inName
,
2344 const char * inDomain
,
2345 const DNSNetworkAddress
* inAddr
,
2346 const char * inInterfaceName
,
2347 DNSHostRegistrationCallBack inCallBack
,
2348 void * inCallBackContext
,
2349 DNSHostRegistrationRef
* outRef
)
2353 DNSHostRegistration
* object
;
2354 mDNSInterfaceID interfaceID
;
2360 // Check parameters.
2363 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2364 require_action( ( inFlags
& ~kDNSHostRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2365 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2366 require_action( inAddr
&& ( inAddr
->addressType
== kDNSNetworkAddressTypeIPv4
), exit
, err
= kDNSUnsupportedErr
);
2367 require_action( !inInterfaceName
||
2368 ( strlen( inInterfaceName
) < sizeof( object
->interfaceName
) ), exit
, err
= kDNSBadParamErr
);
2370 // Default to the local domain when a NULL, empty, or "." domain is passed in.
2372 if( !inDomain
|| ( inDomain
[ 0 ] == '\0' ) || ( inDomain
[ 0 ] == '.' ) )
2374 inDomain
= kDNSLocalDomain
;
2377 // If the caller only wants to add if not found, check if a host with this name was already registered.
2379 MakeDomainNameFromDNSNameString( &name
, inName
);
2380 AppendDNSNameString( &name
, inDomain
);
2382 if( inFlags
& kDNSHostRegistrationFlagOnlyIfNotFound
)
2384 object
= DNSHostRegistrationFindObjectByName( &name
);
2398 // Allocate the object and set it up.
2400 err
= DNSMemAlloc( sizeof( *object
), &object
);
2401 require_noerr( err
, exit
);
2402 memset( object
, 0, sizeof( *object
) );
2404 MakeDomainLabelFromLiteralString( &object
->name
, inName
);
2405 MakeDomainLabelFromLiteralString( &object
->domain
, inDomain
);
2406 object
->refCount
= 1;
2407 object
->flags
= inFlags
;
2408 object
->callback
= inCallBack
;
2409 object
->callbackContext
= inCallBackContext
;
2411 // Set up the interface for interface-specific operations.
2413 if( inInterfaceName
&& ( *inInterfaceName
!= '\0' ) )
2415 strcpy( object
->interfaceName
, inInterfaceName
);
2417 err
= mDNSPlatformInterfaceNameToID( gMDNSPtr
, inInterfaceName
, &interfaceID
);
2418 require_noerr( err
, exit
);
2422 interfaceID
= mDNSInterface_Any
;
2425 // Convert the IP address to a format suitable for mDNS.
2427 ip
.NotAnInteger
= inAddr
->u
.ipv4
.addr
.v32
;
2429 // Set up the resource records and name.
2431 mDNS_SetupResourceRecord( &object
->RR_A
, mDNSNULL
, interfaceID
, kDNSType_A
, 60, kDNSRecordTypeUnique
,
2432 DNSHostRegistrationPrivateCallBack
, object
);
2433 mDNS_SetupResourceRecord( &object
->RR_PTR
, mDNSNULL
, interfaceID
, kDNSType_PTR
, 60, kDNSRecordTypeKnownUnique
,
2434 DNSHostRegistrationPrivateCallBack
, object
);
2436 AssignDomainName( &object
->RR_A
.resrec
.name
, &name
);
2438 mDNS_snprintf( buffer
, sizeof( buffer
), "%d.%d.%d.%d.in-addr.arpa.", ip
.b
[ 3 ], ip
.b
[ 2 ], ip
.b
[ 1 ], ip
.b
[ 0 ] );
2439 MakeDomainNameFromDNSNameString( &object
->RR_PTR
.resrec
.name
, buffer
);
2441 object
->RR_A
.resrec
.rdata
->u
.ipv4
= ip
;
2442 AssignDomainName( &object
->RR_PTR
.resrec
.rdata
->u
.name
, &object
->RR_A
.resrec
.name
);
2444 // Add the object to the list.
2446 object
->next
= gDNSHostRegistrationList
;
2447 gDNSHostRegistrationList
= object
;
2449 // Register with mDNS.
2451 err
= mDNS_Register( gMDNSPtr
, &object
->RR_A
);
2452 require_noerr( err
, exit
);
2454 err
= mDNS_Register( gMDNSPtr
, &object
->RR_PTR
);
2455 if( err
!= mStatus_NoError
)
2457 mDNS_Deregister( gMDNSPtr
, &object
->RR_A
);
2459 require_noerr( err
, exit
);
2469 DNSHostRegistration
** p
;
2471 p
= DNSHostRegistrationFindObject( object
);
2473 DNSMemFree( object
);
2475 DNSServicesUnlock();
2479 //===========================================================================================================================
2480 // DNSHostRegistrationRelease
2481 //===========================================================================================================================
2483 DNSStatus
DNSHostRegistrationRelease( DNSHostRegistrationRef inRef
, DNSHostRegistrationFlags inFlags
)
2486 DNSHostRegistrationRef
* p
;
2489 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2490 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2491 require_action( ( inFlags
& ~kDNSHostRegistrationReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2493 // Decrement the reference count and if it drops to 0, remove the object and deregister with mDNS.
2495 p
= DNSHostRegistrationFindObject( inRef
);
2497 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2499 check( inRef
->refCount
> 0 );
2500 if( --inRef
->refCount
== 0 )
2504 mDNS_Deregister( gMDNSPtr
, &inRef
->RR_A
);
2505 mDNS_Deregister( gMDNSPtr
, &inRef
->RR_PTR
);
2507 // Release the memory used by the object.
2509 DNSMemFree( inRef
);
2514 DNSServicesUnlock();
2518 //===========================================================================================================================
2519 // DNSHostRegistrationFindObject
2521 // Warning: Assumes the DNS lock is held.
2522 //===========================================================================================================================
2524 mDNSlocal DNSHostRegistrationRef
* DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef
)
2526 DNSHostRegistration
** p
;
2528 for( p
= &gDNSHostRegistrationList
; *p
; p
= &( *p
)->next
)
2538 //===========================================================================================================================
2539 // DNSHostRegistrationFindObjectByName
2541 // Warning: Assumes the DNS lock is held.
2542 //===========================================================================================================================
2544 mDNSlocal DNSHostRegistrationRef
DNSHostRegistrationFindObjectByName( const domainname
*inName
)
2546 DNSHostRegistration
* p
;
2550 for( p
= gDNSHostRegistrationList
; p
; p
= p
->next
)
2552 if( SameDomainName( &p
->RR_A
.resrec
.name
, inName
) )
2560 //===========================================================================================================================
2561 // DNSHostRegistrationPrivateCallBack
2562 //===========================================================================================================================
2564 mDNSlocal
void DNSHostRegistrationPrivateCallBack( mDNS
* const inMDNS
, AuthRecord
*const inRR
, mStatus inResult
)
2566 DNSHostRegistrationRef object
;
2568 DNS_UNUSED( inMDNS
);
2572 // Exit if object is no longer valid. Should never happen.
2574 object
= (DNSHostRegistrationRef
) inRR
->RecordContext
;
2575 require( object
, exit
);
2577 // Dispatch based on the status code.
2579 if( inResult
== mStatus_NoError
)
2581 debugf( DEBUG_NAME
"host registration callback: \"%##s\" name successfully registered", inRR
->resrec
.name
.c
);
2582 if( object
->callback
)
2584 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, mDNSNULL
);
2587 else if( inResult
== mStatus_NameConflict
)
2589 debugf( DEBUG_NAME
"host registration callback: \"%##s\" name conflict", inRR
->resrec
.name
.c
);
2591 if( object
->flags
& kDNSHostRegistrationFlagAutoRenameOnConflict
)
2596 // De-register any resource records still registered.
2598 if( object
->RR_A
.resrec
.RecordType
)
2600 mDNS_Deregister( gMDNSPtr
, &object
->RR_A
);
2602 if( object
->RR_PTR
.resrec
.RecordType
)
2604 mDNS_Deregister( gMDNSPtr
, &object
->RR_PTR
);
2607 // Rename the host and re-register to try again.
2609 IncrementLabelSuffix( &object
->name
, mDNSfalse
);
2611 AppendDomainLabel( &name
, &object
->name
);
2612 AppendDomainLabel( &name
, &object
->domain
);
2613 AssignDomainName( &object
->RR_PTR
.resrec
.name
, &name
);
2615 err
= mDNS_Register( gMDNSPtr
, &object
->RR_A
);
2618 err
= mDNS_Register( gMDNSPtr
, &object
->RR_PTR
);
2623 if( object
->callback
)
2625 object
->callback( object
->callbackContext
, object
, kDNSNameConflictErr
, mDNSNULL
);
2631 debugf( DEBUG_NAME
"host registration callback: \"%##s\" unknown result", inRR
->resrec
.name
.c
, inResult
);
2635 DNSServicesUnlock();
2640 #pragma mark == Utilities ==
2643 //===========================================================================================================================
2645 //===========================================================================================================================
2647 mDNSlocal DNSStatus
DNSMemAlloc( size_t inSize
, void *outMem
)
2651 check( inSize
> 0 );
2654 mem
= malloc( inSize
);
2655 *( (void **) outMem
) = mem
;
2658 return( kDNSNoErr
);
2660 return( kDNSNoMemoryErr
);
2663 //===========================================================================================================================
2665 //===========================================================================================================================
2667 mDNSlocal
void DNSMemFree( void *inMem
)
2674 //===========================================================================================================================
2675 // DNSDynamicTextRecordBuildEscaped
2676 //===========================================================================================================================
2678 DNSStatus
DNSDynamicTextRecordBuildEscaped( const char *inFormat
, void *outTextRecord
, size_t *outSize
)
2686 // Calculate the size of the built text record, allocate a buffer for it, then build it in that buffer.
2688 err
= DNSTextRecordValidate( inFormat
, 0x7FFFFFFF, NULL
, &size
);
2689 require_noerr( err
, exit
);
2691 textRecord
= malloc( size
);
2692 require_action( textRecord
, exit
, err
= kDNSNoMemoryErr
);
2694 err
= DNSTextRecordValidate( inFormat
, size
, textRecord
, &size
);
2695 require_noerr( err
, exit
);
2701 *( (void **) outTextRecord
) = textRecord
;
2717 //===========================================================================================================================
2718 // DNSDynamicTextRecordAppendCString
2719 //===========================================================================================================================
2721 DNSStatus
DNSDynamicTextRecordAppendCString( void *ioTxt
, size_t *ioTxtSize
, const char *inName
, const char *inValue
)
2726 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2727 require_action( inValue
, exit
, err
= kDNSBadParamErr
);
2729 if( inValue
!= kDNSTextRecordStringNoValue
)
2731 valueSize
= strlen( inValue
);
2735 valueSize
= kDNSTextRecordNoSize
;
2737 err
= DNSDynamicTextRecordAppendData( ioTxt
, ioTxtSize
, inName
, inValue
, valueSize
);
2738 require_noerr( err
, exit
);
2744 //===========================================================================================================================
2745 // DNSDynamicTextRecordAppendData
2746 //===========================================================================================================================
2749 DNSDynamicTextRecordAppendData(
2752 const char * inName
,
2753 const void * inValue
,
2754 size_t inValueSize
)
2764 require_action( ioTxt
, exit
, err
= kDNSBadParamErr
);
2765 require_action( ioTxtSize
, exit
, err
= kDNSBadParamErr
);
2766 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2768 // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
2770 hasName
= ( inName
!= kDNSTextRecordStringNoValue
) && ( *inName
!= '\0' );
2771 hasValue
= ( inValue
!= kDNSTextRecordNoValue
) && ( inValueSize
!= kDNSTextRecordNoSize
);
2772 require_action( hasName
|| hasValue
, exit
, err
= kDNSUnsupportedErr
);
2774 // Calculate the size needed for the new data (old size + length byte + name size + '=' + value size).
2776 oldSize
= *ioTxtSize
;
2777 newSize
= oldSize
+ 1; // add length byte size
2780 newSize
+= strlen( inName
); // add name size
2783 newSize
+= 1; // add '=' size
2788 newSize
+= inValueSize
; // add value size
2791 // Reallocate the buffer to make room for the new data.
2793 bufferPtr
= (void **) ioTxt
;
2794 newBuffer
= realloc( *bufferPtr
, newSize
);
2795 require_action( newBuffer
, exit
, err
= kDNSNoMemoryErr
);
2796 *bufferPtr
= newBuffer
;
2798 err
= DNSTextRecordAppendData( newBuffer
, oldSize
, newSize
, inName
, inValue
, inValueSize
, &newSize
);
2799 require_noerr( err
, exit
);
2803 *ioTxtSize
= newSize
;
2809 //===========================================================================================================================
2810 // DNSDynamicTextRecordRelease
2811 //===========================================================================================================================
2813 void DNSDynamicTextRecordRelease( void *inTxt
)
2821 //===========================================================================================================================
2822 // DNSTextRecordAppendCString
2823 //===========================================================================================================================
2826 DNSTextRecordAppendCString(
2829 size_t inTxtMaxSize
,
2830 const char * inName
,
2831 const char * inValue
,
2832 size_t * outTxtSize
)
2837 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2838 require_action( inValue
, exit
, err
= kDNSBadParamErr
);
2840 if( inValue
!= kDNSTextRecordStringNoValue
)
2842 valueSize
= strlen( inValue
);
2846 valueSize
= kDNSTextRecordNoSize
;
2848 err
= DNSTextRecordAppendData( inTxt
, inTxtSize
, inTxtMaxSize
, inName
, inValue
, valueSize
, outTxtSize
);
2849 require_noerr( err
, exit
);
2855 //===========================================================================================================================
2856 // DNSTextRecordAppendData
2857 //===========================================================================================================================
2860 DNSTextRecordAppendData(
2863 size_t inTxtMaxSize
,
2864 const char * inName
,
2865 const void * inValue
,
2867 size_t * outTxtSize
)
2877 require_action( inTxt
, exit
, err
= kDNSBadParamErr
);
2878 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2880 // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
2882 hasName
= ( inName
!= kDNSTextRecordStringNoValue
) && ( *inName
!= '\0' );
2883 hasValue
= ( inValue
!= kDNSTextRecordNoValue
) && ( inValueSize
!= kDNSTextRecordNoSize
);
2884 require_action( hasName
|| hasValue
, exit
, err
= kDNSUnsupportedErr
);
2886 // Calculate the size and make sure there is enough total room and enough room in an individual segment.
2891 size
+= strlen( inName
); // add name size
2894 size
+= 1; // add '=' size
2899 size
+= inValueSize
; // add value size
2901 newSize
= inTxtSize
+ 1 + size
; // old size + length byte + new data
2903 require_action( size
< 256, exit
, err
= kDNSNoMemoryErr
);
2904 require_action( newSize
<= inTxtMaxSize
, exit
, err
= kDNSNoMemoryErr
);
2906 // Write the length-prefix byte containing the size of this segment.
2908 p
= ( (mDNSu8
*) inTxt
) + inTxtSize
;
2909 *p
++ = (mDNSu8
) size
;
2915 q
= (const mDNSu8
*) inName
;
2929 q
= (const mDNSu8
*) inValue
;
2930 while( inValueSize
-- > 0 )
2940 *outTxtSize
= newSize
;
2948 //===========================================================================================================================
2949 // DNSTextRecordEscape
2950 //===========================================================================================================================
2952 DNSStatus
DNSTextRecordEscape( const void *inTextRecord
, size_t inTextSize
, char **outEscapedString
)
2955 const DNSUInt8
* src
;
2956 const DNSUInt8
* end
;
2957 DNSUInt8
* dstStorage
;
2961 check( inTextRecord
|| ( inTextSize
== 0 ) );
2963 // Mac OS X uses a single null-terminated string to hold all the text record data with a \001 byte to delimit
2964 // individual records within the entire block. The following code converts a packed array of length-prefixed
2965 // records into a single \001-delimited, null-terminated string. Allocate size + 1 for the null terminator.
2967 dstStorage
= (DNSUInt8
*) malloc( inTextSize
+ 1 );
2968 require_action( dstStorage
, exit
, err
= kDNSNoMemoryErr
);
2971 if( inTextSize
> 0 )
2973 src
= (const DNSUInt8
*) inTextRecord
;
2974 end
= src
+ inTextSize
;
2978 if( ( src
+ size
) > end
)
2980 // Malformed TXT record. Most likely an old-style TXT record.
2989 *dst
++ = '\001'; // \001 record separator. May be overwritten later if this is the last record.
2991 check( (size_t)( dst
- dstStorage
) <= inTextSize
);
2994 // Malformed TXT record. Assume an old-style TXT record and use the TXT record as a whole.
2996 memcpy( dstStorage
, inTextRecord
, inTextSize
);
2997 dstStorage
[ inTextSize
] = '\0';
3001 dstStorage
[ inTextSize
- 1 ] = '\0';
3006 // No text record data so just return an empty string.
3013 if( outEscapedString
)
3015 *outEscapedString
= (char *) dstStorage
;
3028 //===========================================================================================================================
3030 //===========================================================================================================================
3032 DNSStatus
DNSNameValidate( const char *inName
)
3038 p
= MakeDomainNameFromDNSNameString( &name
, inName
);
3045 err
= kDNSBadParamErr
;
3050 //===========================================================================================================================
3051 // DNSServiceTypeValidate
3052 //===========================================================================================================================
3054 DNSStatus
DNSServiceTypeValidate( const char *inServiceType
)
3062 // Construct a fake fully-qualified domain name with a known good domain and the service type to be verified since
3063 // there is currently no canned way to test just a service type by itself.
3065 p
= MakeDomainNameFromDNSNameString( &type
, inServiceType
);
3068 err
= kDNSBadParamErr
;
3072 p
= MakeDomainNameFromDNSNameString( &domain
, "local." );
3075 err
= kDNSBadParamErr
;
3079 p
= ConstructServiceName( &fqdn
, mDNSNULL
, &type
, &domain
);
3082 err
= kDNSBadParamErr
;
3092 //===========================================================================================================================
3093 // DNSTextRecordValidate
3094 //===========================================================================================================================
3096 DNSStatus
DNSTextRecordValidate( const char *inText
, size_t inMaxSize
, void *outRecord
, size_t *outActualSize
)
3105 require_action( inText
, exit
, err
= kDNSBadParamErr
);
3107 // A DNS TXT record consists of a packed block of length-prefixed strings of up to 255 characters each. To allow
3108 // this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate
3109 // individual character strings within the C-string.
3113 dst
= (mDNSu8
*) outRecord
;
3116 p
= (const mDNSu8
*) inText
;
3120 if( totalSize
>= inMaxSize
)
3122 err
= kDNSBadParamErr
;
3128 // Separator Escape sequence, start a new string section.
3130 if( sectionSize
<= 0 )
3132 err
= kDNSBadParamErr
;
3138 section
= &dst
[ totalSize
];
3144 if( sectionSize
>= 255 )
3146 err
= kDNSBadParamErr
;
3152 section
[ 0 ] = sectionSize
;
3153 section
[ sectionSize
] = *p
;
3164 *outActualSize
= totalSize
;
3172 //===========================================================================================================================
3173 // MDNSAddrToDNSAddress
3174 //===========================================================================================================================
3176 mDNSlocal
void MDNSAddrToDNSAddress( const mDNSAddr
*inAddr
, mDNSIPPort inPort
, DNSNetworkAddress
*outAddr
)
3178 switch( inAddr
->type
)
3180 case mDNSAddrType_IPv4
:
3181 outAddr
->addressType
= kDNSNetworkAddressTypeIPv4
;
3182 outAddr
->u
.ipv4
.addr
.v32
= inAddr
->ip
.v4
.NotAnInteger
;
3183 outAddr
->u
.ipv4
.port
.v16
= inPort
.NotAnInteger
;
3186 case mDNSAddrType_IPv6
:
3187 outAddr
->addressType
= kDNSNetworkAddressTypeIPv6
;
3188 outAddr
->u
.ipv6
.addr
.v32
[ 0 ] = inAddr
->ip
.v6
.l
[ 0 ];
3189 outAddr
->u
.ipv6
.addr
.v32
[ 1 ] = inAddr
->ip
.v6
.l
[ 1 ];
3190 outAddr
->u
.ipv6
.addr
.v32
[ 2 ] = inAddr
->ip
.v6
.l
[ 2 ];
3191 outAddr
->u
.ipv6
.addr
.v32
[ 3 ] = inAddr
->ip
.v6
.l
[ 3 ];
3192 outAddr
->u
.ipv6
.port
.v16
= inPort
.NotAnInteger
;
3196 outAddr
->addressType
= kDNSNetworkAddressTypeInvalid
;