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: DNSServiceDiscovery.c,v $
26 Revision 1.8 2004/09/17 01:08:58 cheshire
27 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
28 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
29 declared in that file are ONLY appropriate to single-address-space embedded applications.
30 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
32 Revision 1.7 2004/05/08 12:24:48 bradley
33 Removed trailing character from zero value to fix compile error.
35 Revision 1.6 2004/05/06 18:42:58 ksekar
36 General dns_sd.h API cleanup, including the following radars:
37 <rdar://problem/3592068>: Remove flags with zero value
38 <rdar://problem/3479569>: Passing in NULL causes a crash.
40 Revision 1.5 2004/01/30 02:56:34 bradley
41 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
43 Revision 1.4 2003/11/14 20:59:10 cheshire
44 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
45 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
47 Revision 1.3 2003/10/04 04:47:08 bradley
48 Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
50 Revision 1.2 2003/08/20 07:06:34 bradley
51 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
53 Revision 1.1 2003/08/20 06:04:45 bradley
54 Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
62 #if( macintosh || __MACH__ )
64 #include <sys/types.h>
65 #include <sys/socket.h>
66 #include <netinet/in.h>
68 #elif( defined( _MSC_VER ) || defined( __MWERKS__ ) )
70 #pragma warning( disable:4054 ) // Disable "type cast : from function pointer to data pointer".
71 #pragma warning( disable:4055 ) // Disable "type cast : from data pointer to function pointer".
72 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
73 #pragma warning( disable:4152 ) // Disable "nonstandard extension, function/data pointer conversion in expression".
75 #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
81 #include "mDNSEmbeddedAPI.h"
82 #include "DNSServices.h"
84 #include "DNSServiceDiscovery.h"
91 #pragma mark == Constants & Types ==
94 //===========================================================================================================================
96 //===========================================================================================================================
98 #define DEBUG_NAME "[DNSServiceDiscovery] "
102 kDNSServiceDiscoveryObjectTypeRegistration
= 1,
103 kDNSServiceDiscoveryObjectTypeDomainEnumeration
= 2,
104 kDNSServiceDiscoveryObjectTypeBrowser
= 3,
105 kDNSServiceDiscoveryObjectTypeResolver
= 4
107 } DNSServiceDiscoveryObjectType
;
109 typedef struct _dns_service_discovery_t _dns_service_discovery_t
;
110 struct _dns_service_discovery_t
112 DNSServiceDiscoveryObjectType type
;
119 #pragma mark == Macros ==
122 //===========================================================================================================================
124 //===========================================================================================================================
126 // Emulate Mac OS debugging macros for non-Mac platforms.
128 #if( !TARGET_OS_MAC )
129 #define check(assertion)
130 #define check_string( assertion, cstring )
131 #define check_noerr(err)
132 #define check_noerr_string( error, cstring )
133 #define debug_string( cstring )
134 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
135 #define require_string( assertion, label, string ) require(assertion, label)
136 #define require_quiet( assertion, label ) require( assertion, label )
137 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
138 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
139 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
140 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
141 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
142 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
143 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
147 #pragma mark == Prototypes ==
150 //===========================================================================================================================
152 //===========================================================================================================================
155 DNSServiceRegistrationPrivateCallBack(
157 DNSRegistrationRef inRef
,
158 DNSStatus inStatusCode
,
159 const DNSRegistrationEvent
* inEvent
);
162 DNSServiceDomainEnumerationPrivateCallBack(
165 DNSStatus inStatusCode
,
166 const DNSBrowserEvent
* inEvent
);
169 DNSServiceBrowserPrivateCallBack(
172 DNSStatus inStatusCode
,
173 const DNSBrowserEvent
* inEvent
);
176 DNSServiceResolverPrivateCallBack(
178 DNSResolverRef inRef
,
179 DNSStatus inStatusCode
,
180 const DNSResolverEvent
* inEvent
);
186 //===========================================================================================================================
187 // DNSServiceRegistrationCreate
188 //===========================================================================================================================
190 dns_service_discovery_ref
191 DNSServiceRegistrationCreate(
194 const char * inDomain
,
196 const char * inTextRecord
,
197 DNSServiceRegistrationReply inCallBack
,
201 dns_service_discovery_ref result
;
202 dns_service_discovery_ref obj
;
206 DNSRegistrationRef registration
;
212 // Allocate and initialize the object.
214 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
215 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
217 obj
->type
= kDNSServiceDiscoveryObjectTypeRegistration
;
219 obj
->callback
= inCallBack
;
220 obj
->context
= inContext
;
222 // Create the underlying registration. Build a \001-escaped text record if needed.
226 err
= DNSDynamicTextRecordBuildEscaped( inTextRecord
, &txt
, &txtSize
);
227 require_noerr( err
, exit
);
230 port
.v8
[ 0 ] = (DNSUInt8
)( inPort
>> 8 );
231 port
.v8
[ 1 ] = (DNSUInt8
)( inPort
& 0xFF );
232 err
= DNSRegistrationCreate( kDNSRegistrationFlagPreFormattedTextRecord
, inName
, inType
, inDomain
, port
.v16
, txt
,
233 (DNSCount
) txtSize
, NULL
, NULL
, DNSServiceRegistrationPrivateCallBack
, obj
, ®istration
);
234 require_noerr( err
, exit
);
235 obj
->ref
= registration
;
245 DNSDynamicTextRecordRelease( txt
);
249 DNSServiceDiscoveryDeallocate( obj
);
254 //===========================================================================================================================
255 // DNSServiceRegistrationPrivateCallBack
256 //===========================================================================================================================
259 DNSServiceRegistrationPrivateCallBack(
261 DNSRegistrationRef inRef
,
262 DNSStatus inStatusCode
,
263 const DNSRegistrationEvent
* inEvent
)
265 dns_service_discovery_ref obj
;
266 DNSServiceRegistrationReply callback
;
269 DNS_UNUSED( inStatusCode
);
272 obj
= (dns_service_discovery_ref
) inContext
;
273 check( obj
->callback
);
274 callback
= (DNSServiceRegistrationReply
) obj
->callback
;
276 switch( inEvent
->type
)
278 case kDNSRegistrationEventTypeRegistered
:
279 debugf( DEBUG_NAME
"name registered and active\n" );
283 callback( kDNSServiceDiscoveryNoError
, obj
->context
);
287 case kDNSRegistrationEventTypeNameCollision
:
288 debugf( DEBUG_NAME
"name in use, please choose another name\n" );
292 callback( kDNSServiceDiscoveryNameConflict
, obj
->context
);
301 //===========================================================================================================================
302 // DNSServiceRegistrationAddRecord
303 //===========================================================================================================================
306 DNSServiceRegistrationAddRecord(
307 dns_service_discovery_ref inRef
,
310 const char * inRData
,
314 DNS_UNUSED( inRRType
);
315 DNS_UNUSED( inRDLength
);
316 DNS_UNUSED( inRData
);
319 debugf( DEBUG_NAME
"DNSServiceRegistrationAddRecord is currently not supported\n" );
323 //===========================================================================================================================
324 // DNSServiceRegistrationUpdateRecord
325 //===========================================================================================================================
327 DNSServiceRegistrationReplyErrorType
328 DNSServiceRegistrationUpdateRecord(
329 dns_service_discovery_ref inRef
,
330 DNSRecordReference inRecordRef
,
332 const char * inRData
,
336 DNS_UNUSED( inRecordRef
);
337 DNS_UNUSED( inRDLength
);
338 DNS_UNUSED( inRData
);
341 debugf( DEBUG_NAME
"DNSServiceRegistrationUpdateRecord is currently not supported\n" );
342 return( kDNSServiceDiscoveryUnsupportedErr
);
345 //===========================================================================================================================
346 // DNSServiceRegistrationRemoveRecord
347 //===========================================================================================================================
349 DNSServiceRegistrationReplyErrorType
350 DNSServiceRegistrationRemoveRecord(
351 dns_service_discovery_ref inRef
,
352 DNSRecordReference inRecordRef
)
355 DNS_UNUSED( inRecordRef
);
357 debugf( DEBUG_NAME
"DNSServiceRegistrationRemoveRecord is currently not supported\n" );
358 return( kDNSServiceDiscoveryUnsupportedErr
);
361 //===========================================================================================================================
362 // DNSServiceDomainEnumerationCreate
363 //===========================================================================================================================
365 dns_service_discovery_ref
366 DNSServiceDomainEnumerationCreate(
367 int inRegistrationDomains
,
368 DNSServiceDomainEnumerationReply inCallBack
,
372 dns_service_discovery_ref result
;
373 dns_service_discovery_ref obj
;
374 DNSBrowserRef browser
;
375 DNSBrowserFlags flags
;
380 // Allocate and initialize the object.
382 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
383 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
385 obj
->type
= kDNSServiceDiscoveryObjectTypeDomainEnumeration
;
387 obj
->callback
= inCallBack
;
388 obj
->context
= inContext
;
390 // Create the underlying browser and start searching for domains.
392 err
= DNSBrowserCreate( 0, DNSServiceDomainEnumerationPrivateCallBack
, obj
, &browser
);
393 require_noerr( err
, exit
);
396 if( inRegistrationDomains
)
398 flags
= kDNSBrowserFlagRegistrationDomainsOnly
;
404 err
= DNSBrowserStartDomainSearch( browser
, flags
);
405 require_noerr( err
, exit
);
416 DNSBrowserRelease( browser
, 0 );
420 DNSServiceDiscoveryDeallocate( obj
);
425 //===========================================================================================================================
426 // DNSServiceDomainEnumerationPrivateCallBack
427 //===========================================================================================================================
430 DNSServiceDomainEnumerationPrivateCallBack(
433 DNSStatus inStatusCode
,
434 const DNSBrowserEvent
* inEvent
)
436 dns_service_discovery_ref obj
;
437 DNSServiceDomainEnumerationReply callback
;
440 DNS_UNUSED( inStatusCode
);
443 obj
= (dns_service_discovery_ref
) inContext
;
444 check( obj
->callback
);
445 callback
= (DNSServiceDomainEnumerationReply
) obj
->callback
;
447 switch( inEvent
->type
)
449 case kDNSBrowserEventTypeAddDomain
:
450 debugf( DEBUG_NAME
"add domain \"%s\"\n", inEvent
->data
.addDomain
.domain
);
454 callback( DNSServiceDomainEnumerationReplyAddDomain
, inEvent
->data
.addDomain
.domain
,
459 case kDNSBrowserEventTypeAddDefaultDomain
:
460 debugf( DEBUG_NAME
"add default domain \"%s\"\n", inEvent
->data
.addDefaultDomain
.domain
);
464 callback( DNSServiceDomainEnumerationReplyAddDomainDefault
, inEvent
->data
.addDefaultDomain
.domain
,
469 case kDNSBrowserEventTypeRemoveDomain
:
470 debugf( DEBUG_NAME
"add default domain \"%s\"\n", inEvent
->data
.removeDomain
.domain
);
474 callback( DNSServiceDomainEnumerationReplyRemoveDomain
, inEvent
->data
.removeDomain
.domain
,
484 //===========================================================================================================================
485 // DNSServiceBrowserCreate
486 //===========================================================================================================================
488 dns_service_discovery_ref
489 DNSServiceBrowserCreate(
491 const char * inDomain
,
492 DNSServiceBrowserReply inCallBack
,
496 dns_service_discovery_ref result
;
497 dns_service_discovery_ref obj
;
498 DNSBrowserRef browser
;
503 // Allocate and initialize the object.
505 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
506 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
508 obj
->type
= kDNSServiceDiscoveryObjectTypeBrowser
;
510 obj
->callback
= inCallBack
;
511 obj
->context
= inContext
;
513 // Create the underlying browser and start searching for domains.
515 err
= DNSBrowserCreate( 0, DNSServiceBrowserPrivateCallBack
, obj
, &browser
);
516 require_noerr( err
, exit
);
519 err
= DNSBrowserStartServiceSearch( browser
, 0, inType
, inDomain
);
520 require_noerr( err
, exit
);
531 DNSBrowserRelease( browser
, 0 );
535 DNSServiceDiscoveryDeallocate( obj
);
540 //===========================================================================================================================
541 // DNSServiceBrowserPrivateCallBack
542 //===========================================================================================================================
545 DNSServiceBrowserPrivateCallBack(
548 DNSStatus inStatusCode
,
549 const DNSBrowserEvent
* inEvent
)
551 dns_service_discovery_ref obj
;
552 DNSServiceBrowserReply callback
;
555 DNS_UNUSED( inStatusCode
);
558 obj
= (dns_service_discovery_ref
) inContext
;
559 check( obj
->callback
);
560 callback
= (DNSServiceBrowserReply
) obj
->callback
;
562 switch( inEvent
->type
)
564 case kDNSBrowserEventTypeAddService
:
565 debugf( DEBUG_NAME
"add service \"%s.%s%s\"\n",
566 inEvent
->data
.addService
.name
,
567 inEvent
->data
.addService
.type
,
568 inEvent
->data
.addService
.domain
);
572 callback( DNSServiceBrowserReplyAddInstance
,
573 inEvent
->data
.addService
.name
,
574 inEvent
->data
.addService
.type
,
575 inEvent
->data
.addService
.domain
,
581 case kDNSBrowserEventTypeRemoveService
:
582 debugf( DEBUG_NAME
"remove service \"%s.%s%s\"\n",
583 inEvent
->data
.removeService
.name
,
584 inEvent
->data
.removeService
.type
,
585 inEvent
->data
.removeService
.domain
);
589 callback( DNSServiceBrowserReplyRemoveInstance
,
590 inEvent
->data
.removeService
.name
,
591 inEvent
->data
.removeService
.type
,
592 inEvent
->data
.removeService
.domain
,
603 //===========================================================================================================================
604 // DNSServiceResolverResolve
605 //===========================================================================================================================
607 dns_service_discovery_ref
608 DNSServiceResolverResolve(
611 const char * inDomain
,
612 DNSServiceResolverReply inCallBack
,
616 dns_service_discovery_ref result
;
617 dns_service_discovery_ref obj
;
618 DNSResolverRef resolver
;
622 // Allocate and initialize the object.
624 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
625 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
627 obj
->type
= kDNSServiceDiscoveryObjectTypeResolver
;
629 obj
->callback
= inCallBack
;
630 obj
->context
= inContext
;
632 // Create the underlying resolver and start searching for domains.
634 err
= DNSResolverCreate( 0, inName
, inType
, inDomain
, DNSServiceResolverPrivateCallBack
, obj
, NULL
, &resolver
);
635 require_noerr( err
, exit
);
646 DNSServiceDiscoveryDeallocate( obj
);
651 //===========================================================================================================================
652 // DNSServiceResolverPrivateCallBack
653 //===========================================================================================================================
656 DNSServiceResolverPrivateCallBack(
658 DNSResolverRef inRef
,
659 DNSStatus inStatusCode
,
660 const DNSResolverEvent
* inEvent
)
662 dns_service_discovery_ref obj
;
663 DNSServiceResolverReply callback
;
664 struct sockaddr_in interfaceAddr
;
665 struct sockaddr_in addr
;
668 DNS_UNUSED( inStatusCode
);
671 obj
= (dns_service_discovery_ref
) inContext
;
672 check( obj
->callback
);
673 callback
= (DNSServiceResolverReply
) obj
->callback
;
675 switch( inEvent
->type
)
677 case kDNSResolverEventTypeResolved
:
678 debugf( DEBUG_NAME
"resolved \"%s.%s%s\"\n",
679 inEvent
->data
.resolved
.name
,
680 inEvent
->data
.resolved
.type
,
681 inEvent
->data
.resolved
.domain
);
683 memset( &interfaceAddr
, 0, sizeof( interfaceAddr
) );
684 interfaceAddr
.sin_family
= AF_INET
;
685 interfaceAddr
.sin_port
= 0;
686 interfaceAddr
.sin_addr
.s_addr
= inEvent
->data
.resolved
.interfaceIP
.u
.ipv4
.addr
.v32
;
688 memset( &addr
, 0, sizeof( addr
) );
689 addr
.sin_family
= AF_INET
;
690 addr
.sin_port
= inEvent
->data
.resolved
.address
.u
.ipv4
.port
.v16
;
691 addr
.sin_addr
.s_addr
= inEvent
->data
.resolved
.address
.u
.ipv4
.addr
.v32
;
695 callback( (struct sockaddr
*) &interfaceAddr
, (struct sockaddr
*) &addr
, inEvent
->data
.resolved
.textRecord
,
705 //===========================================================================================================================
706 // DNSServiceDiscoveryMachPort
707 //===========================================================================================================================
709 mach_port_t
DNSServiceDiscoveryMachPort( dns_service_discovery_ref inRef
)
713 debugf( DEBUG_NAME
"DNSServiceDiscoveryMachPort is not supported\n" );
717 //===========================================================================================================================
718 // DNSServiceDiscoveryDeallocate
719 //===========================================================================================================================
721 void DNSServiceDiscoveryDeallocate( dns_service_discovery_ref inRef
)
723 _dns_service_discovery_t
* obj
;
729 obj
= (_dns_service_discovery_t
*) inRef
;
732 case kDNSServiceDiscoveryObjectTypeRegistration
:
735 err
= DNSRegistrationRelease( (DNSRegistrationRef
) inRef
->ref
, 0 );
741 case kDNSServiceDiscoveryObjectTypeDomainEnumeration
:
744 err
= DNSBrowserRelease( (DNSBrowserRef
) inRef
->ref
, 0 );
750 case kDNSServiceDiscoveryObjectTypeBrowser
:
753 err
= DNSBrowserRelease( (DNSBrowserRef
) inRef
->ref
, 0 );
759 case kDNSServiceDiscoveryObjectTypeResolver
:
762 err
= DNSResolverRelease( (DNSResolverRef
) inRef
->ref
, 0 );
769 debugf( DEBUG_NAME
"unknown object type (%d)\n", obj
->type
);
774 //===========================================================================================================================
775 // DNSServiceDiscovery_handleReply
776 //===========================================================================================================================
778 void DNSServiceDiscovery_handleReply( void *inReplyMessage
)
780 DNS_UNUSED( inReplyMessage
);
782 debugf( DEBUG_NAME
"DNSServiceDiscovery_handleReply is not supported\n" );