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@
23 Change History (most recent first):
25 $Log: DNSServices.c,v $
26 Revision 1.15 2003/08/20 06:44:24 bradley
27 Updated to latest internal version of the Rendezvous for Windows code: Added support for interface
28 specific registrations; Added support for no-such-service registrations; Added support for host
29 name registrations; Added support for host proxy and service proxy registrations; Added support for
30 registration record updates (e.g. TXT record updates); Added support for using either a single C
31 string TXT record, a raw, pre-formatted TXT record potentially containing multiple character string
32 entries, or a C-string containing a Mac OS X-style \001-delimited set of TXT record character
33 strings; Added support in resolve callbacks for providing both a simplified C-string for TXT records
34 and a ptr/size for the raw TXT record data; Added utility routines for dynamically building TXT
35 records from a variety of sources (\001-delimited, individual strings, etc.) and converting TXT
36 records to various formats for use in apps; Added utility routines to validate DNS names, DNS
37 service types, and TXT records; Moved to portable address representation unions (byte-stream vs host
38 order integer) for consistency, to avoid swapping between host and network byte order, and for IPv6
39 support; Removed dependence on modified mDNSCore: define structures and prototypes locally; Added
40 support for automatically renaming services on name conflicts; Detect and correct TXT records from
41 old versions of mDNS that treated a TXT record as an arbitrary block of data, but prevent other
42 malformed TXT records from being accepted; Added many more error codes; Added complete HeaderDoc for
43 all constants, structures, typedefs, macros, and functions. Various other minor cleanup and fixes.
45 Revision 1.14 2003/08/14 02:19:56 cheshire
46 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
48 Revision 1.13 2003/08/12 19:56:29 cheshire
51 Revision 1.12 2003/07/23 00:00:04 cheshire
54 Revision 1.11 2003/07/15 01:55:17 cheshire
55 <rdar://problem/3315777> Need to implement service registration with subtypes
57 Revision 1.10 2003/07/02 21:20:10 cheshire
58 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
60 Revision 1.9 2003/05/26 03:21:30 cheshire
61 Tidy up address structure naming:
62 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
63 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
64 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
66 Revision 1.8 2003/05/06 00:00:51 cheshire
67 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
69 Revision 1.7 2003/03/27 03:30:57 cheshire
70 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
71 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
73 1. Make mDNS_DeregisterInterface() safe to call from a callback
74 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
75 (it never really needed to deregister the interface at all)
77 Revision 1.6 2003/03/22 02:57:45 cheshire
78 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
80 Revision 1.5 2003/02/20 00:59:04 cheshire
81 Brought Windows code up to date so it complies with
82 Josh Graessley's interface changes for IPv6 support.
83 (Actual support for IPv6 on Windows will come later.)
85 Revision 1.4 2002/09/21 20:44:56 zarzycki
88 Revision 1.3 2002/09/20 08:36:50 bradley
89 Fixed debug messages to output the correct information when resolving.
91 Revision 1.2 2002/09/20 05:58:01 bradley
92 DNS Services for Windows
101 #include <CoreServices/CoreServices.h>
104 #include "mDNSClientAPI.h"
105 #include "mDNSPlatformFunctions.h"
107 #include "DNSServices.h"
114 #pragma mark == Preprocessor ==
117 //===========================================================================================================================
119 //===========================================================================================================================
121 #if( defined( _MSC_VER ) )
122 #pragma warning( disable:4068 ) // Disable "unknown pragma" warning for "pragma unused".
123 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
127 #pragma mark == Constants ==
130 //===========================================================================================================================
132 //===========================================================================================================================
134 #define DEBUG_NAME "[DNSServices] "
138 kDNSInitializeValidFlags
= kDNSFlagAdvertise
,
142 kDNSBrowserCreateValidFlags
= 0,
143 kDNSBrowserReleaseValidFlags
= 0,
144 kDNSBrowserStartDomainSearchValidFlags
= kDNSBrowserFlagRegistrationDomainsOnly
,
145 kDNSBrowserStopDomainSearchValidFlags
= 0,
146 kDNSBrowserStartServiceSearchValidFlags
= kDNSBrowserFlagAutoResolve
,
147 kDNSBrowserStopServiceSearchValidFlags
= 0,
151 kDNSResolverCreateValidFlags
= kDNSResolverFlagOneShot
|
152 kDNSResolverFlagOnlyIfUnique
|
153 kDNSResolverFlagAutoReleaseByName
,
154 kDNSResolverReleaseValidFlags
= 0,
156 // Service Registration
158 kDNSRegistrationCreateValidFlags
= kDNSRegistrationFlagPreFormattedTextRecord
|
159 kDNSRegistrationFlagAutoRenameOnConflict
,
160 kDNSNoSuchServiceRegistrationCreateValidFlags
= 0,
161 kDNSRegistrationReleaseValidFlags
= 0,
162 kDNSRegistrationUpdateValidFlags
= 0,
164 kDNSRegistrationFlagPrivateNoSuchService
= ( 1 << 16 ),
166 // Domain Registration
168 kDNSDomainRegistrationCreateValidFlags
= 0,
169 kDNSDomainRegistrationReleaseValidFlags
= 0,
173 kDNSHostRegistrationCreateValidFlags
= kDNSHostRegistrationFlagOnlyIfNotFound
|
174 kDNSHostRegistrationFlagAutoRenameOnConflict
,
175 kDNSHostRegistrationReleaseValidFlags
= 0
178 #define kDNSCountCacheEntryCountDefault 64
181 #pragma mark == Structures ==
184 //===========================================================================================================================
186 //===========================================================================================================================
190 typedef struct DNSBrowser DNSBrowser
;
194 DNSBrowserFlags flags
;
195 DNSBrowserCallBack callback
;
196 void * callbackContext
;
197 mDNSBool isDomainBrowsing
;
198 DNSQuestion domainQuestion
;
199 DNSQuestion defaultDomainQuestion
;
200 DNSBrowserFlags domainSearchFlags
;
201 mDNSBool isServiceBrowsing
;
202 DNSQuestion serviceBrowseQuestion
;
203 DNSBrowserFlags serviceSearchFlags
;
204 char searchDomain
[ 256 ];
205 char searchServiceType
[ 256 ];
210 typedef struct DNSResolver DNSResolver
;
214 DNSResolverFlags flags
;
215 DNSResolverCallBack callback
;
216 void * callbackContext
;
218 ServiceInfoQuery query
;
220 mDNSBool isResolving
;
221 char resolveName
[ 256 ];
222 char resolveType
[ 256 ];
223 char resolveDomain
[ 256 ];
228 typedef struct DNSRegistration DNSRegistration
;
229 struct DNSRegistration
231 DNSRegistration
* next
;
232 DNSRegistrationFlags flags
;
233 DNSRegistrationCallBack callback
;
234 void * callbackContext
;
235 char interfaceName
[ 256 ];
236 ServiceRecordSet set
;
238 // WARNING: Do not add fields after the ServiceRecordSet. This is where oversized TXT record space is allocated.
241 // Domain Registration
243 typedef struct DNSDomainRegistration DNSDomainRegistration
;
244 struct DNSDomainRegistration
246 DNSDomainRegistration
* next
;
247 DNSDomainRegistrationFlags flags
;
251 // Domain Registration
253 typedef struct DNSHostRegistration DNSHostRegistration
;
254 struct DNSHostRegistration
256 DNSHostRegistration
* next
;
260 DNSHostRegistrationCallBack callback
;
261 void * callbackContext
;
262 DNSHostRegistrationFlags flags
;
263 char interfaceName
[ 256 ];
269 #pragma mark == Macros ==
272 //===========================================================================================================================
274 //===========================================================================================================================
276 // Emulate Mac OS debugging macros for non-Mac platforms.
278 #if( !TARGET_OS_MAC )
279 #define check(assertion)
280 #define check_string( assertion, cstring )
281 #define check_noerr(err)
282 #define check_noerr_string( error, cstring )
283 #define debug_string( cstring )
284 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
285 #define require_string( assertion, label, string ) require(assertion, label)
286 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
287 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
288 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
289 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
292 #define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
295 #pragma mark == Prototypes ==
298 //===========================================================================================================================
300 //===========================================================================================================================
304 mDNSlocal
void DNSServicesLock( void );
305 mDNSlocal
void DNSServicesUnlock( void );
306 mDNSlocal
void DNSServicesMDNSCallBack( mDNS
*const inMDNS
, mStatus inStatus
);
307 mDNSlocal
void DNSServicesUpdateInterfaceSpecificObjects( mDNS
*const inMDNS
);
312 DNSBrowserPrivateCallBack(
314 DNSQuestion
* inQuestion
,
315 const ResourceRecord
* const inAnswer
,
316 mDNSBool inAddRecord
);
319 DNSBrowserPrivateResolverCallBack(
321 DNSResolverRef inRef
,
322 DNSStatus inStatusCode
,
323 const DNSResolverEvent
* inEvent
);
325 mDNSlocal DNSBrowserRef
DNSBrowserFindObject( DNSBrowserRef inRef
);
326 mDNSlocal DNSBrowserRef
DNSBrowserRemoveObject( DNSBrowserRef inRef
);
330 mDNSlocal
void DNSResolverPrivateCallBack( mDNS
* const inMDNS
, ServiceInfoQuery
*inQuery
);
331 mDNSlocal DNSResolverRef
DNSResolverFindObject( DNSResolverRef inRef
);
332 mDNSlocal DNSResolverRef
DNSResolverRemoveObject( DNSResolverRef inRef
);
333 mDNSlocal
void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef
);
334 mDNSlocal
void DNSResolverRemoveDependentByName( const domainname
*inName
);
335 mDNSlocal DNSResolverRef
DNSResolverFindObjectByName( const domainname
*inName
);
340 DNSRegistrationPrivateCallBack(
342 ServiceRecordSet
* const inSet
,
346 DNSNoSuchServiceRegistrationPrivateCallBack(
348 AuthRecord
* const inRR
,
351 mDNSlocal
void DNSRegistrationUpdateCallBack( mDNS
* const inMDNS
, AuthRecord
* const inRR
, RData
*inOldData
);
353 mDNSlocal DNSRegistrationRef
* DNSRegistrationFindObject( DNSRegistrationRef inRef
);
354 mDNSlocal DNSRegistrationRef
DNSRegistrationRemoveObject( DNSRegistrationRef inRef
);
356 // Domain Registration
358 mDNSlocal DNSDomainRegistrationRef
DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef
);
362 mDNSlocal DNSHostRegistrationRef
* DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef
);
363 mDNSlocal DNSHostRegistrationRef
DNSHostRegistrationFindObjectByName( const domainname
*inName
);
364 mDNSlocal
void DNSHostRegistrationPrivateCallBack( mDNS
* const inMDNS
, AuthRecord
*const inRR
, mStatus inResult
);
368 mDNSlocal DNSStatus
DNSMemAlloc( size_t inSize
, void *outMem
);
369 mDNSlocal
void DNSMemFree( void *inMem
);
370 mDNSlocal
void MDNSAddrToDNSAddress( const mDNSAddr
*inAddr
, DNSNetworkAddress
*outAddr
);
372 // Platform Accessors
374 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
375 struct mDNSPlatformInterfaceInfo
381 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
382 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
385 #pragma mark == Globals ==
388 //===========================================================================================================================
390 //===========================================================================================================================
392 mDNSexport mDNS gMDNS
;
393 mDNSlocal mDNS
* gMDNSPtr
= mDNSNULL
;
394 mDNSlocal CacheRecord
* gMDNSCache
= mDNSNULL
;
395 mDNSlocal DNSBrowserRef gDNSBrowserList
= mDNSNULL
;
396 mDNSlocal DNSResolverRef gDNSResolverList
= mDNSNULL
;
397 mDNSlocal DNSRegistrationRef gDNSRegistrationList
= mDNSNULL
;
398 mDNSlocal DNSDomainRegistrationRef gDNSDomainRegistrationList
= mDNSNULL
;
399 mDNSlocal DNSHostRegistrationRef gDNSHostRegistrationList
= mDNSNULL
;
403 #pragma mark == General ==
406 //===========================================================================================================================
407 // DNSServicesInitialize
408 //===========================================================================================================================
410 DNSStatus
DNSServicesInitialize( DNSFlags inFlags
, DNSCount inCacheEntryCount
)
415 require_action( ( inFlags
& ~kDNSInitializeValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
417 // Allocate the record cache.
419 if( inCacheEntryCount
== 0 )
421 inCacheEntryCount
= kDNSCountCacheEntryCountDefault
;
423 gMDNSCache
= (CacheRecord
*) malloc( inCacheEntryCount
* sizeof( *gMDNSCache
) );
424 require_action( gMDNSCache
, exit
, err
= kDNSNoMemoryErr
);
428 if( inFlags
& kDNSFlagAdvertise
)
430 advertise
= mDNS_Init_AdvertiseLocalAddresses
;
434 advertise
= mDNS_Init_DontAdvertiseLocalAddresses
;
436 err
= mDNS_Init( &gMDNS
, mDNSNULL
, gMDNSCache
, inCacheEntryCount
, advertise
, DNSServicesMDNSCallBack
, mDNSNULL
);
437 require_noerr( err
, exit
);
438 err
= gMDNS
.mDNSPlatformStatus
;
439 require_noerr( err
, exit
);
446 DNSServicesFinalize();
451 //===========================================================================================================================
452 // DNSServicesFinalize
453 //===========================================================================================================================
455 void DNSServicesFinalize( void )
459 mDNSPlatformLock( &gMDNS
);
461 // Clean up any dangling service registrations.
463 while( gDNSRegistrationList
)
465 DNSRegistrationRef serviceRef
;
467 serviceRef
= gDNSRegistrationList
;
468 DNSRegistrationRelease( serviceRef
, 0UL );
469 check_string( serviceRef
!= gDNSRegistrationList
, "dangling service registration cannot be cleaned up" );
472 // Clean up any dangling domain registrations.
474 while( gDNSDomainRegistrationList
)
476 DNSDomainRegistrationRef domainRef
;
478 domainRef
= gDNSDomainRegistrationList
;
479 DNSDomainRegistrationRelease( domainRef
, 0 );
480 check_string( domainRef
!= gDNSDomainRegistrationList
, "dangling domain registration cannot be cleaned up" );
483 // Clean up any dangling host registrations.
485 while( gDNSHostRegistrationList
)
487 DNSHostRegistrationRef hostRef
;
490 hostRef
= gDNSHostRegistrationList
;
491 refCount
= hostRef
->refCount
;
492 DNSHostRegistrationRelease( hostRef
, 0 );
493 check_string( ( refCount
> 1 ) || ( hostRef
!= gDNSHostRegistrationList
),
494 "dangling host registration cannot be cleaned up" );
497 // Clean up any dangling browsers.
499 while( gDNSBrowserList
)
501 DNSBrowserRef browserRef
;
503 browserRef
= gDNSBrowserList
;
504 DNSBrowserRelease( browserRef
, 0 );
505 check_string( browserRef
!= gDNSBrowserList
, "dangling browser cannot be cleaned up" );
508 // Clean up any dangling resolvers.
510 while( gDNSResolverList
)
512 DNSResolverRef resolverRef
;
514 resolverRef
= gDNSResolverList
;
515 DNSResolverRelease( resolverRef
, 0 );
516 check_string( resolverRef
!= gDNSResolverList
, "dangling resolver cannot be cleaned up" );
519 // Null out our MDNS ptr before releasing the lock so no other threads can sneak in and start operations.
522 mDNSPlatformUnlock( &gMDNS
);
526 mDNS_Close( &gMDNS
);
531 gMDNSCache
= mDNSNULL
;
535 //===========================================================================================================================
537 //===========================================================================================================================
539 mDNSlocal
void DNSServicesLock( void )
543 mDNSPlatformLock( gMDNSPtr
);
547 //===========================================================================================================================
549 //===========================================================================================================================
551 mDNSlocal
void DNSServicesUnlock( void )
555 mDNSPlatformUnlock( gMDNSPtr
);
559 //===========================================================================================================================
560 // DNSServicesMDNSCallBack
561 //===========================================================================================================================
563 mDNSlocal
void DNSServicesMDNSCallBack( mDNS
*const inMDNS
, mStatus inStatus
)
565 DNS_UNUSED( inMDNS
);
566 DNS_UNUSED( inStatus
);
569 debugf( DEBUG_NAME
"MDNS callback (status=%ld)", inStatus
);
571 if( inStatus
== mStatus_ConfigChanged
)
573 DNSServicesUpdateInterfaceSpecificObjects( inMDNS
);
577 //===========================================================================================================================
578 // DNSServicesUpdateInterfaceSpecificObjects
579 //===========================================================================================================================
581 mDNSlocal
void DNSServicesUpdateInterfaceSpecificObjects( mDNS
*const inMDNS
)
583 DNSRegistration
* serviceRegistration
;
587 // Update interface-specific service registrations.
589 for( serviceRegistration
= gDNSRegistrationList
; serviceRegistration
; serviceRegistration
= serviceRegistration
->next
)
591 if( serviceRegistration
->interfaceName
[ 0 ] != '\0' )
594 mDNSInterfaceID interfaceID
;
596 err
= mDNSPlatformInterfaceNameToID( inMDNS
, serviceRegistration
->interfaceName
, &interfaceID
);
598 if( err
== mStatus_NoError
)
600 // Update all the resource records with the new interface ID.
602 serviceRegistration
->set
.RR_ADV
.resrec
.InterfaceID
= interfaceID
;
603 serviceRegistration
->set
.RR_PTR
.resrec
.InterfaceID
= interfaceID
;
604 serviceRegistration
->set
.RR_SRV
.resrec
.InterfaceID
= interfaceID
;
605 serviceRegistration
->set
.RR_TXT
.resrec
.InterfaceID
= interfaceID
;
615 #pragma mark == Browser ==
618 //===========================================================================================================================
620 //===========================================================================================================================
624 DNSBrowserFlags inFlags
,
625 DNSBrowserCallBack inCallBack
,
626 void * inCallBackContext
,
627 DNSBrowserRef
* outRef
)
630 DNSBrowser
* objectPtr
;
633 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
634 require_action( ( inFlags
& ~kDNSBrowserCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
635 require_action( inCallBack
, exit
, err
= kDNSBadParamErr
);
637 // Allocate the object and set it up.
639 err
= DNSMemAlloc( sizeof( *objectPtr
), &objectPtr
);
640 require_noerr( err
, exit
);
641 memset( objectPtr
, 0, sizeof( *objectPtr
) );
643 objectPtr
->flags
= inFlags
;
644 objectPtr
->callback
= inCallBack
;
645 objectPtr
->callbackContext
= inCallBackContext
;
647 // Add the object to the list.
649 objectPtr
->next
= gDNSBrowserList
;
650 gDNSBrowserList
= objectPtr
;
662 //===========================================================================================================================
664 //===========================================================================================================================
666 DNSStatus
DNSBrowserRelease( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
669 DNSBrowserEvent event
;
672 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
673 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
674 require_action( ( inFlags
& ~kDNSBrowserReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
676 // Stop service and domain browsing and remove any resolvers dependent on this browser.
678 DNSBrowserStopDomainSearch( inRef
, 0 );
679 DNSBrowserStopServiceSearch( inRef
, 0 );
680 DNSResolverRemoveDependentByBrowser( inRef
);
682 // Remove the object from the list.
684 inRef
= DNSBrowserRemoveObject( inRef
);
685 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
687 // Call the callback with a release event.
689 check( inRef
->callback
);
690 memset( &event
, 0, sizeof( event
) );
691 event
.type
= kDNSBrowserEventTypeRelease
;
692 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
694 // Release the memory used by the object.
704 //===========================================================================================================================
705 // DNSBrowserStartDomainSearch
706 //===========================================================================================================================
708 DNSStatus
DNSBrowserStartDomainSearch( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
711 mDNS_DomainType type
;
712 mDNS_DomainType defaultType
;
713 DNSBrowserEvent event
;
714 mDNSBool isDomainBrowsing
;
716 isDomainBrowsing
= mDNSfalse
;
719 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
720 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
721 require_action( ( inFlags
& ~kDNSBrowserStartDomainSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
722 require_action( !inRef
->isDomainBrowsing
, exit
, err
= kDNSBadStateErr
);
724 // Determine whether to browse for normal domains or registration domains.
726 if( inFlags
& kDNSBrowserFlagRegistrationDomainsOnly
)
728 type
= mDNS_DomainTypeRegistration
;
729 defaultType
= mDNS_DomainTypeRegistrationDefault
;
733 type
= mDNS_DomainTypeBrowse
;
734 defaultType
= mDNS_DomainTypeBrowseDefault
;
737 // Start the browse operations.
739 err
= mDNS_GetDomains( gMDNSPtr
, &inRef
->domainQuestion
, type
, mDNSInterface_Any
, DNSBrowserPrivateCallBack
, inRef
);
740 require_noerr( err
, exit
);
741 isDomainBrowsing
= mDNStrue
;
743 err
= mDNS_GetDomains( gMDNSPtr
, &inRef
->defaultDomainQuestion
, defaultType
, mDNSInterface_Any
, DNSBrowserPrivateCallBack
, inRef
);
744 require_noerr( err
, exit
);
746 inRef
->domainSearchFlags
= inFlags
;
747 inRef
->isDomainBrowsing
= mDNStrue
;
749 // Call back immediately with "local." since that is always available for all types of browsing.
751 memset( &event
, 0, sizeof( event
) );
752 event
.type
= kDNSBrowserEventTypeAddDefaultDomain
;
753 event
.data
.addDefaultDomain
.domain
= kDNSLocalDomain
;
754 event
.data
.addDefaultDomain
.flags
= 0;
755 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
758 if( err
&& isDomainBrowsing
)
760 mDNS_StopGetDomains( gMDNSPtr
, &inRef
->domainQuestion
);
766 //===========================================================================================================================
767 // DNSBrowserStopDomainSearch
768 //===========================================================================================================================
770 DNSStatus
DNSBrowserStopDomainSearch( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
775 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
776 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
777 require_action( ( inFlags
& ~kDNSBrowserStopDomainSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
778 if( !inRef
->isDomainBrowsing
)
780 err
= kDNSBadStateErr
;
784 // Stop the browse operations.
786 mDNS_StopGetDomains( gMDNSPtr
, &inRef
->defaultDomainQuestion
);
787 mDNS_StopGetDomains( gMDNSPtr
, &inRef
->domainQuestion
);
788 inRef
->isDomainBrowsing
= mDNSfalse
;
796 //===========================================================================================================================
797 // DNSBrowserStartServiceSearch
798 //===========================================================================================================================
801 DNSBrowserStartServiceSearch(
803 DNSBrowserFlags inFlags
,
805 const char * inDomain
)
812 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
813 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
814 require_action( ( inFlags
& ~kDNSBrowserStartServiceSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
815 require_action( !inRef
->isServiceBrowsing
, exit
, err
= kDNSBadStateErr
);
816 require_action( inType
, exit
, err
= kDNSBadParamErr
);
818 // Default to the local domain when null is passed in.
820 if( !inDomain
|| ( inDomain
[ 0 ] == '\0' ) || ( inDomain
[ 0 ] == '.' ) )
822 inDomain
= kDNSLocalDomain
;
825 // Save off the search criteria (in case it needs to be automatically restarted later).
827 inRef
->serviceSearchFlags
= inFlags
;
829 strncpy( inRef
->searchServiceType
, inType
, sizeof( inRef
->searchServiceType
) - 1 );
830 inRef
->searchServiceType
[ sizeof( inRef
->searchServiceType
) - 1 ] = '\0';
832 strncpy( inRef
->searchDomain
, inDomain
, sizeof( inRef
->searchDomain
) - 1 );
833 inRef
->searchDomain
[ sizeof( inRef
->searchDomain
) - 1 ] = '\0';
835 // Start the browse operation with mDNS using our private callback.
837 MakeDomainNameFromDNSNameString( &type
, inType
);
838 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
840 err
= mDNS_StartBrowse( gMDNSPtr
, &inRef
->serviceBrowseQuestion
, &type
, &domain
, mDNSInterface_Any
,
841 DNSBrowserPrivateCallBack
, inRef
);
842 require_noerr( err
, exit
);
844 inRef
->isServiceBrowsing
= mDNStrue
;
851 //===========================================================================================================================
852 // DNSBrowserStopServiceSearch
853 //===========================================================================================================================
855 DNSStatus
DNSBrowserStopServiceSearch( DNSBrowserRef inRef
, DNSBrowserFlags inFlags
)
860 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
861 require_action( inRef
&& DNSBrowserFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
862 require_action( ( inFlags
& ~kDNSBrowserStopServiceSearchValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
863 if( !inRef
->isServiceBrowsing
)
865 err
= kDNSBadStateErr
;
869 // Stop the browse operation with mDNS. Remove any resolvers dependent on browser since we are no longer searching.
871 mDNS_StopBrowse( gMDNSPtr
, &inRef
->serviceBrowseQuestion
);
872 DNSResolverRemoveDependentByBrowser( inRef
);
873 inRef
->isServiceBrowsing
= mDNSfalse
;
881 //===========================================================================================================================
882 // DNSBrowserPrivateCallBack
883 //===========================================================================================================================
886 DNSBrowserPrivateCallBack(
888 DNSQuestion
* inQuestion
,
889 const ResourceRecord
* const inAnswer
,
890 mDNSBool inAddRecord
)
892 DNSBrowserRef objectPtr
;
896 char nameString
[ 256 ];
897 char typeString
[ 256 ];
898 char domainString
[ 256 ];
899 DNSBrowserEvent event
;
908 // Exclude non-PTR answers.
910 require( inAnswer
->rrtype
== kDNSType_PTR
, exit
);
912 // Exit if object is no longer valid. Should never happen.
914 objectPtr
= DNSBrowserFindObject( (DNSBrowserRef
) inQuestion
->QuestionContext
);
915 require( objectPtr
, exit
);
917 // Determine what type of callback it is based on the question.
919 memset( &event
, 0, sizeof( event
) );
920 if( inQuestion
== &objectPtr
->serviceBrowseQuestion
)
922 DNSBrowserEventServiceData
* serviceDataPtr
;
923 DNSBrowserFlags browserFlags
;
925 // Extract name, type, and domain from the resource record.
927 DeconstructServiceName( &inAnswer
->rdata
->u
.name
, &name
, &type
, &domain
);
928 ConvertDomainLabelToCString_unescaped( &name
, nameString
);
929 ConvertDomainNameToCString( &type
, typeString
);
930 ConvertDomainNameToCString( &domain
, domainString
);
932 // Fill in the event data. A TTL of zero means the service is no longer available. If the service instance is going
933 // away (ttl == 0), remove any resolvers dependent on the name since it is no longer valid.
937 DNSResolverRemoveDependentByName( &inAnswer
->rdata
->u
.name
);
939 event
.type
= kDNSBrowserEventTypeRemoveService
;
940 serviceDataPtr
= &event
.data
.removeService
;
944 event
.type
= kDNSBrowserEventTypeAddService
;
945 serviceDataPtr
= &event
.data
.addService
;
947 serviceDataPtr
->interfaceName
= "";
948 if( inAnswer
->InterfaceID
!= mDNSInterface_Any
)
950 mDNSPlatformInterfaceInfo info
;
952 err
= mDNSPlatformInterfaceIDToInfo( inMDNS
, inAnswer
->InterfaceID
, &info
);
953 if( err
== mStatus_NoError
)
955 serviceDataPtr
->interfaceName
= info
.name
;
956 MDNSAddrToDNSAddress( &info
.ip
, &serviceDataPtr
->interfaceIP
);
960 serviceDataPtr
->interfaceName
= "";
963 serviceDataPtr
->interfaceID
= inAnswer
->InterfaceID
;
964 serviceDataPtr
->name
= nameString
;
965 serviceDataPtr
->type
= typeString
;
966 serviceDataPtr
->domain
= domainString
;
967 serviceDataPtr
->flags
= 0;
969 // Call the callback.
971 browserFlags
= objectPtr
->serviceSearchFlags
;
972 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
974 // Automatically resolve newly discovered names if the auto-resolve option is enabled.
976 if( ( browserFlags
& kDNSBrowserFlagAutoResolve
) && inAddRecord
)
979 DNSResolverFlags flags
;
981 flags
= kDNSResolverFlagOnlyIfUnique
| kDNSResolverFlagAutoReleaseByName
;
982 err
= DNSResolverCreate( flags
, nameString
, typeString
, domainString
, DNSBrowserPrivateResolverCallBack
,
983 mDNSNULL
, objectPtr
, mDNSNULL
);
989 DNSBrowserEventDomainData
* domainDataPtr
;
991 // Determine the event type. A TTL of zero means the domain is no longer available.
993 domainDataPtr
= mDNSNULL
;
994 if( inQuestion
== &objectPtr
->domainQuestion
)
998 event
.type
= kDNSBrowserEventTypeRemoveDomain
;
999 domainDataPtr
= &event
.data
.removeDomain
;
1003 event
.type
= kDNSBrowserEventTypeAddDomain
;
1004 domainDataPtr
= &event
.data
.addDomain
;
1007 else if( inQuestion
== &objectPtr
->defaultDomainQuestion
)
1011 event
.type
= kDNSBrowserEventTypeRemoveDomain
;
1012 domainDataPtr
= &event
.data
.removeDomain
;
1016 event
.type
= kDNSBrowserEventTypeAddDefaultDomain
;
1017 domainDataPtr
= &event
.data
.addDefaultDomain
;
1020 require_string( domainDataPtr
, exit
, "domain response for unknown question" );
1022 // Extract domain name from the resource record and fill in the event data.
1024 ConvertDomainNameToCString( &inAnswer
->rdata
->u
.name
, domainString
);
1026 domainDataPtr
->interfaceName
= "";
1027 if( inAnswer
->InterfaceID
!= mDNSInterface_Any
)
1029 mDNSPlatformInterfaceInfo info
;
1031 err
= mDNSPlatformInterfaceIDToInfo( inMDNS
, inAnswer
->InterfaceID
, &info
);
1032 if( err
== mStatus_NoError
)
1034 domainDataPtr
->interfaceName
= info
.name
;
1035 MDNSAddrToDNSAddress( &info
.ip
, &domainDataPtr
->interfaceIP
);
1039 domainDataPtr
->interfaceName
= "";
1042 domainDataPtr
->interfaceID
= inAnswer
->InterfaceID
;
1043 domainDataPtr
->domain
= domainString
;
1044 domainDataPtr
->flags
= 0;
1046 // Call the callback.
1048 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1052 DNSServicesUnlock();
1055 //===========================================================================================================================
1056 // DNSBrowserPrivateResolverCallBack
1057 //===========================================================================================================================
1060 DNSBrowserPrivateResolverCallBack(
1062 DNSResolverRef inRef
,
1063 DNSStatus inStatusCode
,
1064 const DNSResolverEvent
* inEvent
)
1066 DNSBrowserRef objectPtr
;
1067 DNSBrowserEvent event
;
1069 DNS_UNUSED( inContext
);
1070 DNS_UNUSED( inStatusCode
);
1074 // Exit if object is no longer valid. Should never happen.
1076 objectPtr
= inRef
->owner
;
1077 require( objectPtr
, exit
);
1079 switch( inEvent
->type
)
1081 case kDNSResolverEventTypeResolved
:
1082 verbosedebugf( DEBUG_NAME
"private resolver callback: resolved (ref=0x%08X)", inRef
);
1083 verbosedebugf( DEBUG_NAME
" name: \"%s\"", inEvent
->data
.resolved
.name
);
1084 verbosedebugf( DEBUG_NAME
" type: \"%s\"", inEvent
->data
.resolved
.type
);
1085 verbosedebugf( DEBUG_NAME
" domain: \"%s\"", inEvent
->data
.resolved
.domain
);
1086 verbosedebugf( DEBUG_NAME
" if: %.4a", &inEvent
->data
.resolved
.interfaceIP
.u
.ipv4
.addr
.v32
);
1087 verbosedebugf( DEBUG_NAME
" ip: %.4a:%u", &inEvent
->data
.resolved
.address
.u
.ipv4
.addr
.v32
,
1088 ( inEvent
->data
.resolved
.address
.u
.ipv4
.port
.v8
[ 0 ] << 8 ) |
1089 inEvent
->data
.resolved
.address
.u
.ipv4
.port
.v8
[ 1 ] );
1090 verbosedebugf( DEBUG_NAME
" text: \"%s\"", inEvent
->data
.resolved
.textRecord
);
1092 // Re-package the resolver event as a browser event and call the callback.
1094 memset( &event
, 0, sizeof( event
) );
1095 event
.type
= kDNSBrowserEventTypeResolved
;
1096 event
.data
.resolved
= &inEvent
->data
.resolved
;
1098 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1101 case kDNSResolverEventTypeRelease
:
1102 verbosedebugf( DEBUG_NAME
"private resolver callback: release (ref=0x%08X)", inRef
);
1106 verbosedebugf( DEBUG_NAME
"private resolver callback: unknown event (ref=0x%08X, event=%ld)", inRef
, inEvent
->type
);
1111 DNSServicesUnlock();
1114 //===========================================================================================================================
1115 // DNSBrowserFindObject
1117 // Warning: Assumes the DNS lock is held.
1118 //===========================================================================================================================
1120 mDNSlocal DNSBrowserRef
DNSBrowserFindObject( DNSBrowserRef inRef
)
1126 // Find the object in the list.
1128 for( p
= gDNSBrowserList
; p
; p
= p
->next
)
1138 //===========================================================================================================================
1139 // DNSBrowserRemoveObject
1141 // Warning: Assumes the DNS lock is held.
1142 //===========================================================================================================================
1144 mDNSlocal DNSBrowserRef
DNSBrowserRemoveObject( DNSBrowserRef inRef
)
1149 for( p
= &gDNSBrowserList
; *p
; p
= &( *p
)->next
)
1166 #pragma mark == Resolver ==
1169 //===========================================================================================================================
1170 // DNSResolverCreate
1171 //===========================================================================================================================
1175 DNSResolverFlags inFlags
,
1176 const char * inName
,
1177 const char * inType
,
1178 const char * inDomain
,
1179 DNSResolverCallBack inCallBack
,
1180 void * inCallBackContext
,
1181 DNSBrowserRef inOwner
,
1182 DNSResolverRef
* outRef
)
1186 DNSResolver
* objectPtr
;
1190 domainname fullName
;
1192 objectPtr
= mDNSNULL
;
1194 // Check parameters.
1197 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1198 require_action( ( inFlags
& ~kDNSResolverCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1199 require_action( inName
, exit
, err
= kDNSBadParamErr
);
1200 require_action( inType
, exit
, err
= kDNSBadParamErr
);
1201 require_action( inDomain
, exit
, err
= kDNSBadParamErr
);
1202 require_action( inCallBack
, exit
, err
= kDNSBadParamErr
);
1203 isAutoRelease
= inOwner
|| ( inFlags
& ( kDNSResolverFlagOneShot
| kDNSResolverFlagAutoReleaseByName
) );
1204 require_action( outRef
|| isAutoRelease
, exit
, err
= kDNSBadParamErr
);
1205 require_action( !inOwner
|| DNSBrowserFindObject( inOwner
), exit
, err
= kDNSBadReferenceErr
);
1207 // Convert and package up the name, type, and domain into a single fully-qualified domain name to resolve.
1209 MakeDomainLabelFromLiteralString( &name
, inName
);
1210 MakeDomainNameFromDNSNameString( &type
, inType
);
1211 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
1212 ConstructServiceName( &fullName
, &name
, &type
, &domain
);
1214 // If the caller only wants to add unique resolvers, check if a resolver for this name is already present.
1216 if( inFlags
& kDNSResolverFlagOnlyIfUnique
)
1218 if( DNSResolverFindObjectByName( &fullName
) )
1229 // Allocate the object and set it up.
1231 err
= DNSMemAlloc( sizeof( *objectPtr
), &objectPtr
);
1232 require_noerr( err
, exit
);
1233 memset( objectPtr
, 0, sizeof( *objectPtr
) );
1235 objectPtr
->flags
= inFlags
;
1236 objectPtr
->callback
= inCallBack
;
1237 objectPtr
->callbackContext
= inCallBackContext
;
1238 objectPtr
->owner
= inOwner
;
1239 AssignDomainName( objectPtr
->info
.name
, fullName
);
1240 objectPtr
->info
.InterfaceID
= mDNSInterface_Any
;
1242 // Save off the resolve info so the callback can get it.
1244 strncpy( objectPtr
->resolveName
, inName
, sizeof( objectPtr
->resolveName
) - 1 );
1245 objectPtr
->resolveName
[ sizeof( objectPtr
->resolveName
) - 1 ] = '\0';
1247 strncpy( objectPtr
->resolveType
, inType
, sizeof( objectPtr
->resolveType
) - 1 );
1248 objectPtr
->resolveType
[ sizeof( objectPtr
->resolveType
) - 1 ] = '\0';
1250 strncpy( objectPtr
->resolveDomain
, inDomain
, sizeof( objectPtr
->resolveDomain
) - 1 );
1251 objectPtr
->resolveDomain
[ sizeof( objectPtr
->resolveDomain
) - 1 ] = '\0';
1253 // Add the object to the list.
1255 objectPtr
->next
= gDNSResolverList
;
1256 gDNSResolverList
= objectPtr
;
1258 // Start the resolving process.
1260 objectPtr
->isResolving
= mDNStrue
;
1261 err
= mDNS_StartResolveService( gMDNSPtr
, &objectPtr
->query
, &objectPtr
->info
, DNSResolverPrivateCallBack
, objectPtr
);
1262 require_noerr( err
, exit
);
1266 *outRef
= objectPtr
;
1270 if( err
&& objectPtr
)
1272 DNSResolverRemoveObject( objectPtr
);
1273 DNSMemFree( objectPtr
);
1275 DNSServicesUnlock();
1279 //===========================================================================================================================
1280 // DNSResolverRelease
1281 //===========================================================================================================================
1283 DNSStatus
DNSResolverRelease( DNSResolverRef inRef
, DNSResolverFlags inFlags
)
1286 DNSResolverEvent event
;
1289 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1290 require_action( ( inFlags
& ~kDNSResolverReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1292 // Remove the object from the list.
1294 inRef
= DNSResolverRemoveObject( inRef
);
1295 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
1297 // Stop the resolving process.
1299 if( inRef
->isResolving
)
1301 inRef
->isResolving
= mDNSfalse
;
1302 mDNS_StopResolveService( gMDNSPtr
, &inRef
->query
);
1305 // Call the callback with a release event.
1307 check( inRef
->callback
);
1308 memset( &event
, 0, sizeof( event
) );
1309 event
.type
= kDNSResolverEventTypeRelease
;
1310 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
1312 // Release the memory used by the object.
1314 DNSMemFree( inRef
);
1318 DNSServicesUnlock();
1322 //===========================================================================================================================
1323 // DNSResolverFindObject
1325 // Warning: Assumes the DNS lock is held.
1326 //===========================================================================================================================
1328 mDNSlocal DNSResolverRef
DNSResolverFindObject( DNSResolverRef inRef
)
1334 // Find the object in the list.
1336 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1346 //===========================================================================================================================
1347 // DNSResolverFindObjectByName
1349 // Warning: Assumes the DNS lock is held.
1350 //===========================================================================================================================
1352 mDNSlocal DNSResolverRef
DNSResolverFindObjectByName( const domainname
*inName
)
1358 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1360 if( SameDomainName( &p
->info
.name
, inName
) )
1368 //===========================================================================================================================
1369 // DNSResolverPrivateCallBack
1370 //===========================================================================================================================
1372 mDNSlocal
void DNSResolverPrivateCallBack( mDNS
* const inMDNS
, ServiceInfoQuery
*inQuery
)
1374 DNSResolverRef objectPtr
;
1375 DNSResolverEvent event
;
1384 // Exit if object is no longer valid. Should never happen.
1386 objectPtr
= DNSResolverFindObject( (DNSResolverRef
) inQuery
->ServiceInfoQueryContext
);
1387 require( objectPtr
, exit
);
1389 // Convert the raw TXT record into a null-terminated string with \001-delimited records for Mac OS X-style clients.
1391 err
= DNSTextRecordEscape( inQuery
->info
->TXTinfo
, inQuery
->info
->TXTlen
, &txtString
);
1394 // Package up the results and call the callback.
1396 memset( &event
, 0, sizeof( event
) );
1397 event
.type
= kDNSResolverEventTypeResolved
;
1398 event
.data
.resolved
.name
= objectPtr
->resolveName
;
1399 event
.data
.resolved
.type
= objectPtr
->resolveType
;
1400 event
.data
.resolved
.domain
= objectPtr
->resolveDomain
;
1401 event
.data
.resolved
.interfaceName
= "";
1402 if( inQuery
->info
->InterfaceID
!= mDNSInterface_Any
)
1404 mDNSPlatformInterfaceInfo info
;
1406 err
= mDNSPlatformInterfaceIDToInfo( inMDNS
, inQuery
->info
->InterfaceID
, &info
);
1407 if( err
== mStatus_NoError
)
1409 event
.data
.resolved
.interfaceName
= info
.name
;
1410 MDNSAddrToDNSAddress( &info
.ip
, &event
.data
.resolved
.interfaceIP
);
1414 event
.data
.resolved
.interfaceName
= "";
1417 event
.data
.resolved
.interfaceID
= inQuery
->info
->InterfaceID
;
1418 event
.data
.resolved
.address
.addressType
= kDNSNetworkAddressTypeIPv4
;
1419 event
.data
.resolved
.address
.u
.ipv4
.addr
.v32
= inQuery
->info
->ip
.ip
.v4
.NotAnInteger
;
1420 event
.data
.resolved
.address
.u
.ipv4
.port
.v16
= inQuery
->info
->port
.NotAnInteger
;
1421 event
.data
.resolved
.textRecord
= txtString
? txtString
: "";
1422 event
.data
.resolved
.flags
= 0;
1423 event
.data
.resolved
.textRecordRaw
= (const void *) inQuery
->info
->TXTinfo
;
1424 event
.data
.resolved
.textRecordRawSize
= (DNSCount
) inQuery
->info
->TXTlen
;
1425 release
= (mDNSBool
)( ( objectPtr
->flags
& kDNSResolverFlagOneShot
) != 0 );
1426 objectPtr
->callback( objectPtr
->callbackContext
, objectPtr
, kDNSNoErr
, &event
);
1428 // Auto-release the object if needed.
1432 DNSResolverRelease( objectPtr
, 0 );
1436 DNSServicesUnlock();
1443 //===========================================================================================================================
1444 // DNSResolverRemoveObject
1446 // Warning: Assumes the DNS lock is held.
1447 //===========================================================================================================================
1449 mDNSlocal DNSResolverRef
DNSResolverRemoveObject( DNSResolverRef inRef
)
1452 DNSResolver
* found
;
1454 for( p
= &gDNSResolverList
; *p
; p
= &( *p
)->next
)
1469 //===========================================================================================================================
1470 // DNSResolverRemoveDependentByBrowser
1472 // Warning: Assumes the DNS lock is held.
1473 //===========================================================================================================================
1475 mDNSlocal
void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef
)
1479 check( inBrowserRef
);
1481 // Removes all the resolver objects dependent on the specified browser. Restart the search from the beginning of the
1482 // list after each removal to handle the list changing in possible callbacks that may be invoked.
1486 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1488 if( p
->owner
== inBrowserRef
)
1490 DNSResolverRelease( p
, 0 );
1498 //===========================================================================================================================
1499 // DNSResolverRemoveDependentByName
1501 // Warning: Assumes the DNS lock is held.
1502 //===========================================================================================================================
1504 mDNSlocal
void DNSResolverRemoveDependentByName( const domainname
*inName
)
1510 // Removes all the resolver objects dependent on the specified name that want to be auto-released by name. Restart
1511 // the search from the beginning of the list after each removal to handle the list changing in possible callbacks
1512 // that may be invoked.
1516 for( p
= gDNSResolverList
; p
; p
= p
->next
)
1518 if( ( p
->flags
& kDNSResolverFlagAutoReleaseByName
) && SameDomainName( &p
->info
.name
, inName
) )
1520 DNSResolverRelease( p
, 0 );
1530 #pragma mark == Registration ==
1533 //===========================================================================================================================
1534 // DNSRegistrationCreate
1535 //===========================================================================================================================
1538 DNSRegistrationCreate(
1539 DNSRegistrationFlags inFlags
,
1540 const char * inName
,
1541 const char * inType
,
1542 const char * inDomain
,
1544 const void * inTextRecord
,
1545 DNSCount inTextRecordSize
,
1546 const char * inHost
,
1547 const char * inInterfaceName
,
1548 DNSRegistrationCallBack inCallBack
,
1549 void * inCallBackContext
,
1550 DNSRegistrationRef
* outRef
)
1554 DNSRegistration
* objectPtr
;
1555 mDNSInterfaceID interfaceID
;
1560 mDNSu8 textRecord
[ 256 ];
1561 const mDNSu8
* textRecordPtr
;
1563 domainname tempHost
;
1565 objectPtr
= mDNSNULL
;
1567 // Check parameters.
1570 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1571 require_action( ( inFlags
& ~kDNSRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1572 require_action( inType
, exit
, err
= kDNSBadParamErr
);
1573 require_action( inTextRecord
|| ( inTextRecordSize
== 0 ), exit
, err
= kDNSBadParamErr
);
1574 require_action( ( inFlags
& kDNSRegistrationFlagPreFormattedTextRecord
) ||
1575 ( inTextRecordSize
< sizeof( textRecord
) ), exit
, err
= kDNSBadParamErr
);
1576 require_action( !inInterfaceName
||
1577 ( strlen( inInterfaceName
) < sizeof( objectPtr
->interfaceName
) ), exit
, err
= kDNSBadParamErr
);
1579 // Default to the local domain when null is passed in.
1583 inDomain
= kDNSLocalDomain
;
1586 // Set up the text record. If the pre-formatted flag is used, the input text is assumed to be a valid text record
1587 // and is used directly. Otherwise, the input text is assumed to be raw text and is converted to a text record.
1589 textRecordPtr
= (const mDNSu8
*) inTextRecord
;
1590 if( !( inFlags
& kDNSRegistrationFlagPreFormattedTextRecord
) )
1592 // Convert the raw input text to a length-prefixed text record.
1594 if( inTextRecordSize
> 0 )
1596 textRecord
[ 0 ] = (mDNSu8
) inTextRecordSize
;
1597 memcpy( &textRecord
[ 1 ], inTextRecord
, inTextRecordSize
);
1598 textRecordPtr
= textRecord
;
1599 inTextRecordSize
+= 1;
1603 // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
1605 size
= sizeof( *objectPtr
);
1606 if( inTextRecordSize
> sizeof( RDataBody
) )
1608 size
+= ( inTextRecordSize
- sizeof( RDataBody
) );
1611 err
= DNSMemAlloc( size
, &objectPtr
);
1612 require_noerr( err
, exit
);
1613 memset( objectPtr
, 0, size
);
1615 objectPtr
->flags
= inFlags
;
1616 objectPtr
->callback
= inCallBack
;
1617 objectPtr
->callbackContext
= inCallBackContext
;
1619 // Set up the interface for interface-specific operations.
1621 if( inInterfaceName
&& ( *inInterfaceName
!= '\0' ) )
1623 strcpy( objectPtr
->interfaceName
, inInterfaceName
);
1625 err
= mDNSPlatformInterfaceNameToID( gMDNSPtr
, inInterfaceName
, &interfaceID
);
1626 require_noerr( err
, exit
);
1630 interfaceID
= mDNSInterface_Any
;
1633 // Add the object to the list.
1635 objectPtr
->next
= gDNSRegistrationList
;
1636 gDNSRegistrationList
= objectPtr
;
1638 // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string,
1639 // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
1640 // If we're using the system name (i.e. name is NULL), automatically rename on conflicts to keep things in sync.
1642 if( !inName
|| ( *inName
== '\0' ) )
1644 name
= gMDNSPtr
->nicelabel
;
1645 inFlags
|= kDNSRegistrationFlagAutoRenameOnConflict
;
1649 MakeDomainLabelFromLiteralString( &name
, inName
);
1651 MakeDomainNameFromDNSNameString( &type
, inType
);
1652 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
1653 port
.b
[ 0 ] = ( mDNSu8
)( inPort
>> 8 );
1654 port
.b
[ 1 ] = ( mDNSu8
)( inPort
>> 0 );
1656 // Set up the host name (if not using the default).
1662 MakeDomainNameFromDNSNameString( host
, inHost
);
1663 AppendDomainName( host
, &domain
);
1666 // Register the service with mDNS.
1668 err
= mDNS_RegisterService( gMDNSPtr
, &objectPtr
->set
, &name
, &type
, &domain
, host
, port
, textRecordPtr
,
1669 (mDNSu16
) inTextRecordSize
, NULL
, 0, interfaceID
,
1670 DNSRegistrationPrivateCallBack
, objectPtr
);
1671 require_noerr( err
, exit
);
1675 *outRef
= objectPtr
;
1679 if( err
&& objectPtr
)
1681 DNSRegistrationRemoveObject( objectPtr
);
1682 DNSMemFree( objectPtr
);
1684 DNSServicesUnlock();
1688 //===========================================================================================================================
1689 // DNSNoSuchServiceRegistrationCreate
1690 //===========================================================================================================================
1693 DNSNoSuchServiceRegistrationCreate(
1694 DNSRegistrationFlags inFlags
,
1695 const char * inName
,
1696 const char * inType
,
1697 const char * inDomain
,
1698 const char * inInterfaceName
,
1699 DNSRegistrationCallBack inCallBack
,
1700 void * inCallBackContext
,
1701 DNSRegistrationRef
* outRef
)
1705 DNSRegistration
* objectPtr
;
1706 mDNSInterfaceID interfaceID
;
1711 objectPtr
= mDNSNULL
;
1713 // Check parameters.
1716 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1717 require_action( ( inFlags
& ~kDNSNoSuchServiceRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1718 inFlags
|= kDNSRegistrationFlagPrivateNoSuchService
;
1719 require_action( inType
, exit
, err
= kDNSBadParamErr
);
1720 require_action( !inInterfaceName
||
1721 ( strlen( inInterfaceName
) < sizeof( objectPtr
->interfaceName
) ), exit
, err
= kDNSBadParamErr
);
1723 // Default to the local domain when null is passed in.
1727 inDomain
= kDNSLocalDomain
;
1730 // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
1732 size
= sizeof( *objectPtr
);
1734 err
= DNSMemAlloc( size
, &objectPtr
);
1735 require_noerr( err
, exit
);
1736 memset( objectPtr
, 0, size
);
1738 objectPtr
->flags
= inFlags
;
1739 objectPtr
->callback
= inCallBack
;
1740 objectPtr
->callbackContext
= inCallBackContext
;
1742 // Set up the interface for interface-specific operations.
1744 if( inInterfaceName
&& ( *inInterfaceName
!= '\0' ) )
1746 strcpy( objectPtr
->interfaceName
, inInterfaceName
);
1748 err
= mDNSPlatformInterfaceNameToID( gMDNSPtr
, inInterfaceName
, &interfaceID
);
1749 require_noerr( err
, exit
);
1753 interfaceID
= mDNSInterface_Any
;
1756 // Add the object to the list.
1758 objectPtr
->next
= gDNSRegistrationList
;
1759 gDNSRegistrationList
= objectPtr
;
1761 // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string,
1762 // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
1764 if( !inName
|| ( *inName
== '\0' ) )
1766 name
= gMDNSPtr
->nicelabel
;
1770 MakeDomainLabelFromLiteralString( &name
, inName
);
1772 MakeDomainNameFromDNSNameString( &type
, inType
);
1773 MakeDomainNameFromDNSNameString( &domain
, inDomain
);
1775 // Register the service with mDNS.
1777 err
= mDNS_RegisterNoSuchService( gMDNSPtr
, &objectPtr
->set
.RR_SRV
, &name
, &type
, &domain
, mDNSNULL
,
1778 interfaceID
, DNSNoSuchServiceRegistrationPrivateCallBack
, objectPtr
);
1779 require_noerr( err
, exit
);
1783 *outRef
= objectPtr
;
1787 if( err
&& objectPtr
)
1789 DNSRegistrationRemoveObject( objectPtr
);
1790 DNSMemFree( objectPtr
);
1792 DNSServicesUnlock();
1796 //===========================================================================================================================
1797 // DNSRegistrationRelease
1798 //===========================================================================================================================
1800 DNSStatus
DNSRegistrationRelease( DNSRegistrationRef inRef
, DNSRegistrationFlags inFlags
)
1803 DNSRegistrationEvent event
;
1806 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1807 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
1808 require_action( ( inFlags
& ~kDNSRegistrationReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1810 // Notify the client of the registration release. Remove the object first so they cannot try to use it in the callback.
1812 inRef
= DNSRegistrationRemoveObject( inRef
);
1813 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
1815 if( inRef
->callback
)
1817 memset( &event
, 0, sizeof( event
) );
1818 event
.type
= kDNSRegistrationEventTypeRelease
;
1819 inRef
->callback( inRef
->callbackContext
, inRef
, kDNSNoErr
, &event
);
1822 // Deregister from mDNS after everything else since it will call us back to free the memory.
1824 if( !( inRef
->flags
& kDNSRegistrationFlagPrivateNoSuchService
) )
1826 err
= mDNS_DeregisterService( gMDNSPtr
, &inRef
->set
);
1827 require_noerr( err
, exit
);
1831 err
= mDNS_DeregisterNoSuchService( gMDNSPtr
, &inRef
->set
.RR_SRV
);
1832 require_noerr( err
, exit
);
1835 // Note: Don't free here. Wait for mDNS to call us back with a mem free result.
1838 DNSServicesUnlock();
1842 //===========================================================================================================================
1843 // DNSRegistrationUpdate
1844 //===========================================================================================================================
1847 DNSRegistrationUpdate(
1848 DNSRegistrationRef inRef
,
1849 DNSRecordFlags inFlags
,
1850 DNSRegistrationRecordRef inRecord
,
1851 const void * inData
,
1853 DNSUInt32 inNewTTL
)
1860 newRData
= mDNSNULL
;
1863 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
1864 require_action( DNSRegistrationFindObject( inRef
), exit
, err
= kDNSBadReferenceErr
);
1865 require_action( ( inFlags
& ~kDNSRegistrationUpdateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
1866 require_action( inData
|| ( inSize
== 0 ), exit
, err
= kDNSBadParamErr
);
1868 // If a non-NULL record is specified, update it. Otherwise, use the standard TXT record.
1872 // $$$ TO DO: Add support for updating extra records (support adding and removing them too).
1875 err
= kDNSUnsupportedErr
;
1876 require_noerr( err
, exit
);
1880 rr
= &inRef
->set
.RR_TXT
;
1883 // Allocate storage for the new data and set it up.
1885 maxRDLength
= sizeof( RDataBody
);
1886 if( inSize
> maxRDLength
)
1888 maxRDLength
= inSize
;
1890 err
= DNSMemAlloc( ( sizeof( *newRData
) - sizeof( RDataBody
) ) + maxRDLength
, &newRData
);
1891 require_noerr( err
, exit
);
1893 newRData
->MaxRDLength
= (mDNSu16
) maxRDLength
;
1894 memcpy( &newRData
->u
, inData
, inSize
);
1896 // Update the record with mDNS.
1898 err
= mDNS_Update( gMDNSPtr
, rr
, inNewTTL
, (mDNSu16
) inSize
, newRData
, DNSRegistrationUpdateCallBack
);
1899 require_noerr( err
, exit
);
1901 newRData
= mDNSNULL
;
1906 DNSMemFree( newRData
);
1908 DNSServicesUnlock();
1912 //===========================================================================================================================
1913 // DNSRegistrationPrivateCallBack
1914 //===========================================================================================================================
1916 mDNSlocal
void DNSRegistrationPrivateCallBack( mDNS
* const inMDNS
, ServiceRecordSet
* const inSet
, mStatus inResult
)
1918 DNSRegistrationRef object
;
1919 DNSRegistrationEvent event
;
1921 DNS_UNUSED( inMDNS
);
1925 // Exit if object is no longer valid. Should never happen.
1927 object
= (DNSRegistrationRef
) inSet
->ServiceContext
;
1928 require( object
, exit
);
1930 // Dispatch based on the status code.
1934 case mStatus_NoError
:
1935 debugf( DEBUG_NAME
"registration callback: \"%##s\" name successfully registered", inSet
->RR_SRV
.resrec
.name
.c
);
1937 // Notify the client of a successful registration.
1939 if( object
->callback
)
1941 memset( &event
, 0, sizeof( event
) );
1942 event
.type
= kDNSRegistrationEventTypeRegistered
;
1943 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
1947 case mStatus_NameConflict
:
1952 debugf( DEBUG_NAME
"registration callback: \"%##s\" name conflict", inSet
->RR_SRV
.resrec
.name
.c
);
1954 // Name conflict. If the auto-rename option is enabled, uniquely rename the service and re-register it. Otherwise,
1955 // remove the object so they cannot try to use it in the callback and notify the client of the name conflict.
1958 if( object
->flags
& kDNSRegistrationFlagAutoRenameOnConflict
)
1960 err
= mDNS_RenameAndReregisterService( inMDNS
, inSet
, mDNSNULL
);
1962 if( err
== mStatus_NoError
)
1964 debugf( DEBUG_NAME
"registration callback: auto-renamed to \"%##s\"", inSet
->RR_SRV
.resrec
.name
.c
);
1970 object
= DNSRegistrationRemoveObject( object
);
1971 require( object
, exit
);
1973 // Notify the client of the name collision.
1975 if( object
->callback
)
1977 memset( &event
, 0, sizeof( event
) );
1978 event
.type
= kDNSRegistrationEventTypeNameCollision
;
1979 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
1982 // Notify the client that the registration is being released.
1984 if( object
->callback
)
1986 memset( &event
, 0, sizeof( event
) );
1987 event
.type
= kDNSRegistrationEventTypeRelease
;
1988 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
1991 // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
1993 DNSMemFree( object
);
1998 case mStatus_MemFree
:
1999 debugf( DEBUG_NAME
"registration callback: \"%##s\" memory free", inSet
->RR_SRV
.resrec
.name
.c
);
2001 if( object
->set
.RR_TXT
.resrec
.rdata
!= &object
->set
.RR_TXT
.rdatastorage
)
2003 // Standard TXT record was updated with new data so free that data separately.
2005 DNSMemFree( object
->set
.RR_TXT
.resrec
.rdata
);
2007 DNSMemFree( object
);
2011 debugf( DEBUG_NAME
"registration callback: \"%##s\" unknown result %d", inSet
->RR_SRV
.resrec
.name
.c
, inResult
);
2016 DNSServicesUnlock();
2019 //===========================================================================================================================
2020 // DNSNoSuchServiceRegistrationPrivateCallBack
2021 //===========================================================================================================================
2023 mDNSlocal
void DNSNoSuchServiceRegistrationPrivateCallBack( mDNS
* const inMDNS
, AuthRecord
* const inRR
, mStatus inResult
)
2025 DNSRegistrationRef object
;
2026 DNSRegistrationEvent event
;
2028 DNS_UNUSED( inMDNS
);
2032 // Exit if object is no longer valid. Should never happen.
2034 object
= (DNSRegistrationRef
) inRR
->RecordContext
;
2035 require( object
, exit
);
2037 // Dispatch based on the status code.
2041 case mStatus_NoError
:
2042 debugf( DEBUG_NAME
"registration callback: \"%##s\" name successfully registered", inRR
->resrec
.name
.c
);
2044 // Notify the client of a successful registration.
2046 if( object
->callback
)
2048 memset( &event
, 0, sizeof( event
) );
2049 event
.type
= kDNSRegistrationEventTypeRegistered
;
2050 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2054 case mStatus_NameConflict
:
2056 debugf( DEBUG_NAME
"registration callback: \"%##s\" name conflict", inRR
->resrec
.name
.c
);
2058 // Name conflict. Name conflicts for no-such-service registrations often do not make sense since the main goal
2059 // is to assert that no other service exists with a name. Because of this, name conflicts should be handled by
2060 // the code registering the no-such-service since it is likely that if another service is already using the
2061 // name that the service registering the no-such-service should rename its other services as well. The name
2062 // collision client callback invoked here can do any of this client-specific behavior. It may be worth adding
2063 // support for the auto-rename feature in the future though, if that becomes necessary.
2065 object
= DNSRegistrationRemoveObject( object
);
2066 require( object
, exit
);
2068 // Notify the client of the name collision.
2070 if( object
->callback
)
2072 memset( &event
, 0, sizeof( event
) );
2073 event
.type
= kDNSRegistrationEventTypeNameCollision
;
2074 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2077 // Notify the client that the registration is being released.
2079 if( object
->callback
)
2081 memset( &event
, 0, sizeof( event
) );
2082 event
.type
= kDNSRegistrationEventTypeRelease
;
2083 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, &event
);
2086 // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
2088 DNSMemFree( object
);
2092 case mStatus_MemFree
:
2093 debugf( DEBUG_NAME
"registration callback: \"%##s\" memory free", inRR
->resrec
.name
.c
);
2095 DNSMemFree( object
);
2099 debugf( DEBUG_NAME
"registration callback: \"%##s\" unknown result %d", inRR
->resrec
.name
.c
, inResult
);
2104 DNSServicesUnlock();
2107 //===========================================================================================================================
2108 // DNSRegistrationUpdateCallBack
2109 //===========================================================================================================================
2111 mDNSlocal
void DNSRegistrationUpdateCallBack( mDNS
* const inMDNS
, AuthRecord
* const inRR
, RData
*inOldData
)
2113 DNS_UNUSED( inMDNS
);
2118 if( inOldData
!= &inRR
->rdatastorage
)
2120 DNSMemFree( inOldData
);
2124 //===========================================================================================================================
2125 // DNSRegistrationFindObject
2127 // Warning: Assumes the DNS lock is held.
2128 //===========================================================================================================================
2130 mDNSlocal DNSRegistrationRef
* DNSRegistrationFindObject( DNSRegistrationRef inRef
)
2132 DNSRegistration
** p
;
2134 for( p
= &gDNSRegistrationList
; *p
; p
= &( *p
)->next
)
2144 //===========================================================================================================================
2145 // DNSRegistrationRemoveObject
2147 // Warning: Assumes the DNS lock is held.
2148 //===========================================================================================================================
2150 mDNSlocal DNSRegistrationRef
DNSRegistrationRemoveObject( DNSRegistrationRef inRef
)
2152 DNSRegistration
** p
;
2153 DNSRegistration
* found
;
2155 for( p
= &gDNSRegistrationList
; *p
; p
= &( *p
)->next
)
2172 #pragma mark == Domain Registration ==
2175 //===========================================================================================================================
2176 // DNSDomainRegistrationCreate
2177 //===========================================================================================================================
2180 DNSDomainRegistrationCreate(
2181 DNSDomainRegistrationFlags inFlags
,
2182 const char * inName
,
2183 DNSDomainRegistrationType inType
,
2184 DNSDomainRegistrationRef
* outRef
)
2187 DNSDomainRegistration
* objectPtr
;
2189 objectPtr
= mDNSNULL
;
2191 // Check parameters.
2194 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2195 require_action( ( inFlags
& ~kDNSDomainRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2196 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2197 require_action( inType
< kDNSDomainRegistrationTypeMax
, exit
, err
= kDNSBadParamErr
);
2199 // Allocate the object and set it up.
2201 err
= DNSMemAlloc( sizeof( *objectPtr
), &objectPtr
);
2202 require_noerr( err
, exit
);
2203 memset( objectPtr
, 0, sizeof( *objectPtr
) );
2205 objectPtr
->flags
= inFlags
;
2207 // Add the object to the list.
2209 objectPtr
->next
= gDNSDomainRegistrationList
;
2210 gDNSDomainRegistrationList
= objectPtr
;
2212 // Register the domain with mDNS.
2214 err
= mDNS_AdvertiseDomains( gMDNSPtr
, &objectPtr
->rr
, (mDNS_DomainType
) inType
, mDNSInterface_Any
, (char *) inName
);
2215 require_noerr( err
, exit
);
2219 *outRef
= objectPtr
;
2223 if( err
&& objectPtr
)
2225 DNSDomainRegistrationRemoveObject( objectPtr
);
2226 DNSMemFree( objectPtr
);
2228 DNSServicesUnlock();
2232 //===========================================================================================================================
2233 // DNSDomainRegistrationRelease
2234 //===========================================================================================================================
2236 DNSStatus
DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef
, DNSDomainRegistrationFlags inFlags
)
2241 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2242 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2243 require_action( ( inFlags
& ~kDNSDomainRegistrationReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2245 // Remove the object and deregister the domain with mDNS.
2247 inRef
= DNSDomainRegistrationRemoveObject( inRef
);
2248 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2250 mDNS_StopAdvertiseDomains( gMDNSPtr
, &inRef
->rr
);
2252 // Release the memory used by the object.
2254 DNSMemFree( inRef
);
2258 DNSServicesUnlock();
2262 //===========================================================================================================================
2263 // DNSDomainRegistrationRemoveObject
2265 // Warning: Assumes the DNS lock is held.
2266 //===========================================================================================================================
2268 mDNSlocal DNSDomainRegistrationRef
DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef
)
2270 DNSDomainRegistration
** p
;
2271 DNSDomainRegistration
* found
;
2273 for( p
= &gDNSDomainRegistrationList
; *p
; p
= &( *p
)->next
)
2290 #pragma mark == Domain Registration ==
2293 //===========================================================================================================================
2294 // DNSHostRegistrationCreate
2295 //===========================================================================================================================
2298 DNSHostRegistrationCreate(
2299 DNSHostRegistrationFlags inFlags
,
2300 const char * inName
,
2301 const char * inDomain
,
2302 const DNSNetworkAddress
* inAddr
,
2303 const char * inInterfaceName
,
2304 DNSHostRegistrationCallBack inCallBack
,
2305 void * inCallBackContext
,
2306 DNSHostRegistrationRef
* outRef
)
2310 DNSHostRegistration
* object
;
2311 mDNSInterfaceID interfaceID
;
2317 // Check parameters.
2320 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2321 require_action( ( inFlags
& ~kDNSHostRegistrationCreateValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2322 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2323 require_action( inAddr
&& ( inAddr
->addressType
== kDNSNetworkAddressTypeIPv4
), exit
, err
= kDNSUnsupportedErr
);
2324 require_action( !inInterfaceName
||
2325 ( strlen( inInterfaceName
) < sizeof( object
->interfaceName
) ), exit
, err
= kDNSBadParamErr
);
2327 // Default to the local domain when null is passed in.
2331 inDomain
= kDNSLocalDomain
;
2334 // If the caller only wants to add if not found, check if a host with this name was already registered.
2336 MakeDomainNameFromDNSNameString( &name
, inName
);
2337 AppendDNSNameString( &name
, inDomain
);
2339 if( inFlags
& kDNSHostRegistrationFlagOnlyIfNotFound
)
2341 object
= DNSHostRegistrationFindObjectByName( &name
);
2355 // Allocate the object and set it up.
2357 err
= DNSMemAlloc( sizeof( *object
), &object
);
2358 require_noerr( err
, exit
);
2359 memset( object
, 0, sizeof( *object
) );
2361 MakeDomainLabelFromLiteralString( &object
->name
, inName
);
2362 MakeDomainLabelFromLiteralString( &object
->domain
, inDomain
);
2363 object
->refCount
= 1;
2364 object
->flags
= inFlags
;
2365 object
->callback
= inCallBack
;
2366 object
->callbackContext
= inCallBackContext
;
2368 // Set up the interface for interface-specific operations.
2370 if( inInterfaceName
&& ( *inInterfaceName
!= '\0' ) )
2372 strcpy( object
->interfaceName
, inInterfaceName
);
2374 err
= mDNSPlatformInterfaceNameToID( gMDNSPtr
, inInterfaceName
, &interfaceID
);
2375 require_noerr( err
, exit
);
2379 interfaceID
= mDNSInterface_Any
;
2382 // Convert the IP address to a format suitable for mDNS.
2384 ip
.NotAnInteger
= inAddr
->u
.ipv4
.addr
.v32
;
2386 // Set up the resource records and name.
2388 mDNS_SetupResourceRecord( &object
->RR_A
, mDNSNULL
, interfaceID
, kDNSType_A
, 60, kDNSRecordTypeUnique
,
2389 DNSHostRegistrationPrivateCallBack
, object
);
2390 mDNS_SetupResourceRecord( &object
->RR_PTR
, mDNSNULL
, interfaceID
, kDNSType_PTR
, 60, kDNSRecordTypeKnownUnique
,
2391 DNSHostRegistrationPrivateCallBack
, object
);
2393 AssignDomainName( object
->RR_A
.resrec
.name
, name
);
2395 mDNS_snprintf( buffer
, sizeof( buffer
), "%d.%d.%d.%d.in-addr.arpa.", ip
.b
[ 3 ], ip
.b
[ 2 ], ip
.b
[ 1 ], ip
.b
[ 0 ] );
2396 MakeDomainNameFromDNSNameString( &object
->RR_PTR
.resrec
.name
, buffer
);
2398 object
->RR_A
.resrec
.rdata
->u
.ip
= ip
;
2399 AssignDomainName( object
->RR_PTR
.resrec
.rdata
->u
.name
, object
->RR_A
.resrec
.name
);
2401 // Add the object to the list.
2403 object
->next
= gDNSHostRegistrationList
;
2404 gDNSHostRegistrationList
= object
;
2406 // Register with mDNS.
2408 err
= mDNS_Register( gMDNSPtr
, &object
->RR_A
);
2409 require_noerr( err
, exit
);
2411 err
= mDNS_Register( gMDNSPtr
, &object
->RR_PTR
);
2412 if( err
!= mStatus_NoError
)
2414 mDNS_Deregister( gMDNSPtr
, &object
->RR_A
);
2416 require_noerr( err
, exit
);
2426 DNSHostRegistration
** p
;
2428 p
= DNSHostRegistrationFindObject( object
);
2430 DNSMemFree( object
);
2432 DNSServicesUnlock();
2436 //===========================================================================================================================
2437 // DNSHostRegistrationRelease
2438 //===========================================================================================================================
2440 DNSStatus
DNSHostRegistrationRelease( DNSHostRegistrationRef inRef
, DNSHostRegistrationFlags inFlags
)
2443 DNSHostRegistrationRef
* p
;
2446 require_action( gMDNSPtr
, exit
, err
= kDNSNotInitializedErr
);
2447 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2448 require_action( ( inFlags
& ~kDNSHostRegistrationReleaseValidFlags
) == 0, exit
, err
= kDNSBadFlagsErr
);
2450 // Decrement the reference count and if it drops to 0, remove the object and deregister with mDNS.
2452 p
= DNSHostRegistrationFindObject( inRef
);
2454 require_action( inRef
, exit
, err
= kDNSBadReferenceErr
);
2456 check( inRef
->refCount
> 0 );
2457 if( --inRef
->refCount
== 0 )
2461 mDNS_Deregister( gMDNSPtr
, &inRef
->RR_A
);
2462 mDNS_Deregister( gMDNSPtr
, &inRef
->RR_PTR
);
2464 // Release the memory used by the object.
2466 DNSMemFree( inRef
);
2471 DNSServicesUnlock();
2475 //===========================================================================================================================
2476 // DNSHostRegistrationFindObject
2478 // Warning: Assumes the DNS lock is held.
2479 //===========================================================================================================================
2481 mDNSlocal DNSHostRegistrationRef
* DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef
)
2483 DNSHostRegistration
** p
;
2485 for( p
= &gDNSHostRegistrationList
; *p
; p
= &( *p
)->next
)
2495 //===========================================================================================================================
2496 // DNSHostRegistrationFindObjectByName
2498 // Warning: Assumes the DNS lock is held.
2499 //===========================================================================================================================
2501 mDNSlocal DNSHostRegistrationRef
DNSHostRegistrationFindObjectByName( const domainname
*inName
)
2503 DNSHostRegistration
* p
;
2507 for( p
= gDNSHostRegistrationList
; p
; p
= p
->next
)
2509 if( SameDomainName( &p
->RR_A
.resrec
.name
, inName
) )
2517 //===========================================================================================================================
2518 // DNSHostRegistrationPrivateCallBack
2519 //===========================================================================================================================
2521 mDNSlocal
void DNSHostRegistrationPrivateCallBack( mDNS
* const inMDNS
, AuthRecord
*const inRR
, mStatus inResult
)
2523 DNSHostRegistrationRef object
;
2525 DNS_UNUSED( inMDNS
);
2529 // Exit if object is no longer valid. Should never happen.
2531 object
= (DNSHostRegistrationRef
) inRR
->RecordContext
;
2532 require( object
, exit
);
2534 // Dispatch based on the status code.
2536 if( inResult
== mStatus_NoError
)
2538 debugf( DEBUG_NAME
"host registration callback: \"%##s\" name successfully registered", inRR
->resrec
.name
.c
);
2539 if( object
->callback
)
2541 object
->callback( object
->callbackContext
, object
, kDNSNoErr
, mDNSNULL
);
2544 else if( inResult
== mStatus_NameConflict
)
2546 debugf( DEBUG_NAME
"host registration callback: \"%##s\" name conflict", inRR
->resrec
.name
.c
);
2548 if( object
->flags
& kDNSHostRegistrationFlagAutoRenameOnConflict
)
2553 // De-register any resource records still registered.
2555 if( object
->RR_A
.resrec
.RecordType
)
2557 mDNS_Deregister( gMDNSPtr
, &object
->RR_A
);
2559 if( object
->RR_PTR
.resrec
.RecordType
)
2561 mDNS_Deregister( gMDNSPtr
, &object
->RR_PTR
);
2564 // Rename the host and re-register to try again.
2566 IncrementLabelSuffix( &object
->name
, mDNSfalse
);
2568 AppendDomainLabel( &name
, &object
->name
);
2569 AppendDomainLabel( &name
, &object
->domain
);
2570 AssignDomainName( object
->RR_PTR
.resrec
.name
, name
);
2572 err
= mDNS_Register( gMDNSPtr
, &object
->RR_A
);
2575 err
= mDNS_Register( gMDNSPtr
, &object
->RR_PTR
);
2580 if( object
->callback
)
2582 object
->callback( object
->callbackContext
, object
, kDNSNameConflictErr
, mDNSNULL
);
2588 debugf( DEBUG_NAME
"host registration callback: \"%##s\" unknown result", inRR
->resrec
.name
.c
, inResult
);
2592 DNSServicesUnlock();
2597 #pragma mark == Utilities ==
2600 //===========================================================================================================================
2602 //===========================================================================================================================
2604 mDNSlocal DNSStatus
DNSMemAlloc( size_t inSize
, void *outMem
)
2608 check( inSize
> 0 );
2611 mem
= malloc( inSize
);
2612 *( (void **) outMem
) = mem
;
2615 return( kDNSNoErr
);
2617 return( kDNSNoMemoryErr
);
2620 //===========================================================================================================================
2622 //===========================================================================================================================
2624 mDNSlocal
void DNSMemFree( void *inMem
)
2631 //===========================================================================================================================
2632 // DNSDynamicTextRecordBuildEscaped
2633 //===========================================================================================================================
2635 DNSStatus
DNSDynamicTextRecordBuildEscaped( const char *inFormat
, void *outTextRecord
, size_t *outSize
)
2643 // Calculate the size of the built text record, allocate a buffer for it, then build it in that buffer.
2645 err
= DNSTextRecordValidate( inFormat
, 0x7FFFFFFF, NULL
, &size
);
2646 require_noerr( err
, exit
);
2648 textRecord
= malloc( size
);
2649 require_action( textRecord
, exit
, err
= kDNSNoMemoryErr
);
2651 err
= DNSTextRecordValidate( inFormat
, size
, textRecord
, &size
);
2652 require_noerr( err
, exit
);
2658 *( (void **) outTextRecord
) = textRecord
;
2674 //===========================================================================================================================
2675 // DNSDynamicTextRecordAppendCString
2676 //===========================================================================================================================
2678 DNSStatus
DNSDynamicTextRecordAppendCString( void *ioTxt
, size_t *ioTxtSize
, const char *inName
, const char *inValue
)
2683 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2684 require_action( inValue
, exit
, err
= kDNSBadParamErr
);
2686 if( inValue
!= kDNSTextRecordStringNoValue
)
2688 valueSize
= strlen( inValue
);
2692 valueSize
= kDNSTextRecordNoSize
;
2694 err
= DNSDynamicTextRecordAppendData( ioTxt
, ioTxtSize
, inName
, inValue
, valueSize
);
2695 require_noerr( err
, exit
);
2701 //===========================================================================================================================
2702 // DNSDynamicTextRecordAppendData
2703 //===========================================================================================================================
2706 DNSDynamicTextRecordAppendData(
2709 const char * inName
,
2710 const void * inValue
,
2711 size_t inValueSize
)
2721 require_action( ioTxt
, exit
, err
= kDNSBadParamErr
);
2722 require_action( ioTxtSize
, exit
, err
= kDNSBadParamErr
);
2723 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2725 // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
2727 hasName
= ( inName
!= kDNSTextRecordStringNoValue
) && ( *inName
!= '\0' );
2728 hasValue
= ( inValue
!= kDNSTextRecordNoValue
) && ( inValueSize
!= kDNSTextRecordNoSize
);
2729 require_action( hasName
|| hasValue
, exit
, err
= kDNSUnsupportedErr
);
2731 // Calculate the size needed for the new data (old size + length byte + name size + '=' + value size).
2733 oldSize
= *ioTxtSize
;
2734 newSize
= oldSize
+ 1; // add length byte size
2737 newSize
+= strlen( inName
); // add name size
2740 newSize
+= 1; // add '=' size
2745 newSize
+= inValueSize
; // add value size
2748 // Reallocate the buffer to make room for the new data.
2750 bufferPtr
= (void **) ioTxt
;
2751 newBuffer
= realloc( *bufferPtr
, newSize
);
2752 require_action( newBuffer
, exit
, err
= kDNSNoMemoryErr
);
2753 *bufferPtr
= newBuffer
;
2755 err
= DNSTextRecordAppendData( newBuffer
, oldSize
, newSize
, inName
, inValue
, inValueSize
, &newSize
);
2756 require_noerr( err
, exit
);
2760 *ioTxtSize
= newSize
;
2766 //===========================================================================================================================
2767 // DNSDynamicTextRecordRelease
2768 //===========================================================================================================================
2770 void DNSDynamicTextRecordRelease( void *inTxt
)
2778 //===========================================================================================================================
2779 // DNSTextRecordAppendCString
2780 //===========================================================================================================================
2783 DNSTextRecordAppendCString(
2786 size_t inTxtMaxSize
,
2787 const char * inName
,
2788 const char * inValue
,
2789 size_t * outTxtSize
)
2794 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2795 require_action( inValue
, exit
, err
= kDNSBadParamErr
);
2797 if( inValue
!= kDNSTextRecordStringNoValue
)
2799 valueSize
= strlen( inValue
);
2803 valueSize
= kDNSTextRecordNoSize
;
2805 err
= DNSTextRecordAppendData( inTxt
, inTxtSize
, inTxtMaxSize
, inName
, inValue
, valueSize
, outTxtSize
);
2806 require_noerr( err
, exit
);
2812 //===========================================================================================================================
2813 // DNSTextRecordAppendData
2814 //===========================================================================================================================
2817 DNSTextRecordAppendData(
2820 size_t inTxtMaxSize
,
2821 const char * inName
,
2822 const void * inValue
,
2824 size_t * outTxtSize
)
2834 require_action( inTxt
, exit
, err
= kDNSBadParamErr
);
2835 require_action( inName
, exit
, err
= kDNSBadParamErr
);
2837 // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
2839 hasName
= ( inName
!= kDNSTextRecordStringNoValue
) && ( *inName
!= '\0' );
2840 hasValue
= ( inValue
!= kDNSTextRecordNoValue
) && ( inValueSize
!= kDNSTextRecordNoSize
);
2841 require_action( hasName
|| hasValue
, exit
, err
= kDNSUnsupportedErr
);
2843 // Calculate the size and make sure there is enough total room and enough room in an individual segment.
2848 size
+= strlen( inName
); // add name size
2851 size
+= 1; // add '=' size
2856 size
+= inValueSize
; // add value size
2858 newSize
= inTxtSize
+ 1 + size
; // old size + length byte + new data
2860 require_action( size
< 256, exit
, err
= kDNSNoMemoryErr
);
2861 require_action( newSize
<= inTxtMaxSize
, exit
, err
= kDNSNoMemoryErr
);
2863 // Write the length-prefix byte containing the size of this segment.
2865 p
= ( (mDNSu8
*) inTxt
) + inTxtSize
;
2866 *p
++ = (mDNSu8
) size
;
2872 q
= (const mDNSu8
*) inName
;
2886 q
= (const mDNSu8
*) inValue
;
2887 while( inValueSize
-- > 0 )
2897 *outTxtSize
= newSize
;
2905 //===========================================================================================================================
2906 // DNSTextRecordEscape
2907 //===========================================================================================================================
2909 DNSStatus
DNSTextRecordEscape( const void *inTextRecord
, size_t inTextSize
, char **outEscapedString
)
2912 const DNSUInt8
* src
;
2913 const DNSUInt8
* end
;
2914 DNSUInt8
* dstStorage
;
2918 check( inTextRecord
|| ( inTextSize
== 0 ) );
2920 // Mac OS X uses a single null-terminated string to hold all the text record data with a \001 byte to delimit
2921 // individual records within the entire block. The following code converts a packed array of length-prefixed
2922 // records into a single \001-delimited, null-terminated string. Allocate size + 1 for the null terminator.
2924 dstStorage
= (DNSUInt8
*) malloc( inTextSize
+ 1 );
2925 require_action( dstStorage
, exit
, err
= kDNSNoMemoryErr
);
2928 if( inTextSize
> 0 )
2930 src
= (const DNSUInt8
*) inTextRecord
;
2931 end
= src
+ inTextSize
;
2935 if( ( src
+ size
) > end
)
2937 // Malformed TXT record. Most likely an old-style TXT record.
2946 *dst
++ = '\001'; // \001 record separator. May be overwritten later if this is the last record.
2948 check( ( dst
- dstStorage
) <= inTextSize
);
2951 // Malformed TXT record. Assume an old-style TXT record and use the TXT record as a whole.
2953 memcpy( dstStorage
, inTextRecord
, inTextSize
);
2954 dstStorage
[ inTextSize
] = '\0';
2958 dstStorage
[ inTextSize
- 1 ] = '\0';
2963 // No text record data so just return an empty string.
2970 if( outEscapedString
)
2972 *outEscapedString
= (char *) dstStorage
;
2985 //===========================================================================================================================
2987 //===========================================================================================================================
2989 DNSStatus
DNSNameValidate( const char *inName
)
2995 p
= MakeDomainNameFromDNSNameString( &name
, inName
);
3002 err
= kDNSBadParamErr
;
3007 //===========================================================================================================================
3008 // DNSServiceTypeValidate
3009 //===========================================================================================================================
3011 DNSStatus
DNSServiceTypeValidate( const char *inServiceType
)
3019 // Construct a fake fully-qualified domain name with a known good domain and the service type to be verified since
3020 // there is currently no canned way to test just a service type by itself.
3022 p
= MakeDomainNameFromDNSNameString( &type
, inServiceType
);
3025 err
= kDNSBadParamErr
;
3029 p
= MakeDomainNameFromDNSNameString( &domain
, "local." );
3032 err
= kDNSBadParamErr
;
3036 p
= ConstructServiceName( &fqdn
, mDNSNULL
, &type
, &domain
);
3039 err
= kDNSBadParamErr
;
3049 //===========================================================================================================================
3050 // DNSTextRecordValidate
3051 //===========================================================================================================================
3053 DNSStatus
DNSTextRecordValidate( const char *inText
, size_t inMaxSize
, void *outRecord
, size_t *outActualSize
)
3062 require_action( inText
, exit
, err
= kDNSBadParamErr
);
3064 // A DNS TXT record consists of a packed block of length-prefixed strings of up to 255 characters each. To allow
3065 // this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate
3066 // individual character strings within the C-string.
3070 dst
= (mDNSu8
*) outRecord
;
3073 p
= (const mDNSu8
*) inText
;
3077 if( totalSize
>= inMaxSize
)
3079 err
= kDNSBadParamErr
;
3085 // Separator Escape sequence, start a new string section.
3087 if( sectionSize
<= 0 )
3089 err
= kDNSBadParamErr
;
3095 section
= &dst
[ totalSize
];
3101 if( sectionSize
>= 255 )
3103 err
= kDNSBadParamErr
;
3109 section
[ 0 ] = sectionSize
;
3110 section
[ sectionSize
] = *p
;
3121 *outActualSize
= totalSize
;
3129 //===========================================================================================================================
3130 // MDNSAddrToDNSAddress
3131 //===========================================================================================================================
3133 mDNSlocal
void MDNSAddrToDNSAddress( const mDNSAddr
*inAddr
, DNSNetworkAddress
*outAddr
)
3135 switch( inAddr
->type
)
3137 case mDNSAddrType_IPv4
:
3138 outAddr
->addressType
= kDNSNetworkAddressTypeIPv4
;
3139 outAddr
->u
.ipv4
.addr
.v32
= inAddr
->ip
.v4
.NotAnInteger
;
3142 case mDNSAddrType_IPv6
:
3143 outAddr
->addressType
= kDNSNetworkAddressTypeIPv6
;
3144 outAddr
->u
.ipv6
.addr
.v32
[ 0 ] = inAddr
->ip
.v6
.l
[ 0 ];
3145 outAddr
->u
.ipv6
.addr
.v32
[ 1 ] = inAddr
->ip
.v6
.l
[ 1 ];
3146 outAddr
->u
.ipv6
.addr
.v32
[ 2 ] = inAddr
->ip
.v6
.l
[ 2 ];
3147 outAddr
->u
.ipv6
.addr
.v32
[ 3 ] = inAddr
->ip
.v6
.l
[ 3 ];
3151 outAddr
->addressType
= kDNSNetworkAddressTypeInvalid
;