1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: DNSServiceDiscovery.c,v $
20 Revision 1.9 2006/08/14 23:26:01 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.8 2004/09/17 01:08:58 cheshire
24 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
25 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
26 declared in that file are ONLY appropriate to single-address-space embedded applications.
27 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
29 Revision 1.7 2004/05/08 12:24:48 bradley
30 Removed trailing character from zero value to fix compile error.
32 Revision 1.6 2004/05/06 18:42:58 ksekar
33 General dns_sd.h API cleanup, including the following radars:
34 <rdar://problem/3592068>: Remove flags with zero value
35 <rdar://problem/3479569>: Passing in NULL causes a crash.
37 Revision 1.5 2004/01/30 02:56:34 bradley
38 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
40 Revision 1.4 2003/11/14 20:59:10 cheshire
41 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
42 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
44 Revision 1.3 2003/10/04 04:47:08 bradley
45 Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
47 Revision 1.2 2003/08/20 07:06:34 bradley
48 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
50 Revision 1.1 2003/08/20 06:04:45 bradley
51 Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
59 #if( macintosh || __MACH__ )
61 #include <sys/types.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
65 #elif( defined( _MSC_VER ) || defined( __MWERKS__ ) )
67 #pragma warning( disable:4054 ) // Disable "type cast : from function pointer to data pointer".
68 #pragma warning( disable:4055 ) // Disable "type cast : from data pointer to function pointer".
69 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
70 #pragma warning( disable:4152 ) // Disable "nonstandard extension, function/data pointer conversion in expression".
72 #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
78 #include "mDNSEmbeddedAPI.h"
79 #include "DNSServices.h"
81 #include "DNSServiceDiscovery.h"
88 #pragma mark == Constants & Types ==
91 //===========================================================================================================================
93 //===========================================================================================================================
95 #define DEBUG_NAME "[DNSServiceDiscovery] "
99 kDNSServiceDiscoveryObjectTypeRegistration
= 1,
100 kDNSServiceDiscoveryObjectTypeDomainEnumeration
= 2,
101 kDNSServiceDiscoveryObjectTypeBrowser
= 3,
102 kDNSServiceDiscoveryObjectTypeResolver
= 4
104 } DNSServiceDiscoveryObjectType
;
106 typedef struct _dns_service_discovery_t _dns_service_discovery_t
;
107 struct _dns_service_discovery_t
109 DNSServiceDiscoveryObjectType type
;
116 #pragma mark == Macros ==
119 //===========================================================================================================================
121 //===========================================================================================================================
123 // Emulate Mac OS debugging macros for non-Mac platforms.
125 #if( !TARGET_OS_MAC )
126 #define check(assertion)
127 #define check_string( assertion, cstring )
128 #define check_noerr(err)
129 #define check_noerr_string( error, cstring )
130 #define debug_string( cstring )
131 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
132 #define require_string( assertion, label, string ) require(assertion, label)
133 #define require_quiet( assertion, label ) require( assertion, label )
134 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
135 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
136 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
137 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
138 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
139 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
140 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
144 #pragma mark == Prototypes ==
147 //===========================================================================================================================
149 //===========================================================================================================================
152 DNSServiceRegistrationPrivateCallBack(
154 DNSRegistrationRef inRef
,
155 DNSStatus inStatusCode
,
156 const DNSRegistrationEvent
* inEvent
);
159 DNSServiceDomainEnumerationPrivateCallBack(
162 DNSStatus inStatusCode
,
163 const DNSBrowserEvent
* inEvent
);
166 DNSServiceBrowserPrivateCallBack(
169 DNSStatus inStatusCode
,
170 const DNSBrowserEvent
* inEvent
);
173 DNSServiceResolverPrivateCallBack(
175 DNSResolverRef inRef
,
176 DNSStatus inStatusCode
,
177 const DNSResolverEvent
* inEvent
);
183 //===========================================================================================================================
184 // DNSServiceRegistrationCreate
185 //===========================================================================================================================
187 dns_service_discovery_ref
188 DNSServiceRegistrationCreate(
191 const char * inDomain
,
193 const char * inTextRecord
,
194 DNSServiceRegistrationReply inCallBack
,
198 dns_service_discovery_ref result
;
199 dns_service_discovery_ref obj
;
203 DNSRegistrationRef registration
;
209 // Allocate and initialize the object.
211 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
212 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
214 obj
->type
= kDNSServiceDiscoveryObjectTypeRegistration
;
216 obj
->callback
= inCallBack
;
217 obj
->context
= inContext
;
219 // Create the underlying registration. Build a \001-escaped text record if needed.
223 err
= DNSDynamicTextRecordBuildEscaped( inTextRecord
, &txt
, &txtSize
);
224 require_noerr( err
, exit
);
227 port
.v8
[ 0 ] = (DNSUInt8
)( inPort
>> 8 );
228 port
.v8
[ 1 ] = (DNSUInt8
)( inPort
& 0xFF );
229 err
= DNSRegistrationCreate( kDNSRegistrationFlagPreFormattedTextRecord
, inName
, inType
, inDomain
, port
.v16
, txt
,
230 (DNSCount
) txtSize
, NULL
, NULL
, DNSServiceRegistrationPrivateCallBack
, obj
, ®istration
);
231 require_noerr( err
, exit
);
232 obj
->ref
= registration
;
242 DNSDynamicTextRecordRelease( txt
);
246 DNSServiceDiscoveryDeallocate( obj
);
251 //===========================================================================================================================
252 // DNSServiceRegistrationPrivateCallBack
253 //===========================================================================================================================
256 DNSServiceRegistrationPrivateCallBack(
258 DNSRegistrationRef inRef
,
259 DNSStatus inStatusCode
,
260 const DNSRegistrationEvent
* inEvent
)
262 dns_service_discovery_ref obj
;
263 DNSServiceRegistrationReply callback
;
266 DNS_UNUSED( inStatusCode
);
269 obj
= (dns_service_discovery_ref
) inContext
;
270 check( obj
->callback
);
271 callback
= (DNSServiceRegistrationReply
) obj
->callback
;
273 switch( inEvent
->type
)
275 case kDNSRegistrationEventTypeRegistered
:
276 debugf( DEBUG_NAME
"name registered and active\n" );
280 callback( kDNSServiceDiscoveryNoError
, obj
->context
);
284 case kDNSRegistrationEventTypeNameCollision
:
285 debugf( DEBUG_NAME
"name in use, please choose another name\n" );
289 callback( kDNSServiceDiscoveryNameConflict
, obj
->context
);
298 //===========================================================================================================================
299 // DNSServiceRegistrationAddRecord
300 //===========================================================================================================================
303 DNSServiceRegistrationAddRecord(
304 dns_service_discovery_ref inRef
,
307 const char * inRData
,
311 DNS_UNUSED( inRRType
);
312 DNS_UNUSED( inRDLength
);
313 DNS_UNUSED( inRData
);
316 debugf( DEBUG_NAME
"DNSServiceRegistrationAddRecord is currently not supported\n" );
320 //===========================================================================================================================
321 // DNSServiceRegistrationUpdateRecord
322 //===========================================================================================================================
324 DNSServiceRegistrationReplyErrorType
325 DNSServiceRegistrationUpdateRecord(
326 dns_service_discovery_ref inRef
,
327 DNSRecordReference inRecordRef
,
329 const char * inRData
,
333 DNS_UNUSED( inRecordRef
);
334 DNS_UNUSED( inRDLength
);
335 DNS_UNUSED( inRData
);
338 debugf( DEBUG_NAME
"DNSServiceRegistrationUpdateRecord is currently not supported\n" );
339 return( kDNSServiceDiscoveryUnsupportedErr
);
342 //===========================================================================================================================
343 // DNSServiceRegistrationRemoveRecord
344 //===========================================================================================================================
346 DNSServiceRegistrationReplyErrorType
347 DNSServiceRegistrationRemoveRecord(
348 dns_service_discovery_ref inRef
,
349 DNSRecordReference inRecordRef
)
352 DNS_UNUSED( inRecordRef
);
354 debugf( DEBUG_NAME
"DNSServiceRegistrationRemoveRecord is currently not supported\n" );
355 return( kDNSServiceDiscoveryUnsupportedErr
);
358 //===========================================================================================================================
359 // DNSServiceDomainEnumerationCreate
360 //===========================================================================================================================
362 dns_service_discovery_ref
363 DNSServiceDomainEnumerationCreate(
364 int inRegistrationDomains
,
365 DNSServiceDomainEnumerationReply inCallBack
,
369 dns_service_discovery_ref result
;
370 dns_service_discovery_ref obj
;
371 DNSBrowserRef browser
;
372 DNSBrowserFlags flags
;
377 // Allocate and initialize the object.
379 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
380 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
382 obj
->type
= kDNSServiceDiscoveryObjectTypeDomainEnumeration
;
384 obj
->callback
= inCallBack
;
385 obj
->context
= inContext
;
387 // Create the underlying browser and start searching for domains.
389 err
= DNSBrowserCreate( 0, DNSServiceDomainEnumerationPrivateCallBack
, obj
, &browser
);
390 require_noerr( err
, exit
);
393 if( inRegistrationDomains
)
395 flags
= kDNSBrowserFlagRegistrationDomainsOnly
;
401 err
= DNSBrowserStartDomainSearch( browser
, flags
);
402 require_noerr( err
, exit
);
413 DNSBrowserRelease( browser
, 0 );
417 DNSServiceDiscoveryDeallocate( obj
);
422 //===========================================================================================================================
423 // DNSServiceDomainEnumerationPrivateCallBack
424 //===========================================================================================================================
427 DNSServiceDomainEnumerationPrivateCallBack(
430 DNSStatus inStatusCode
,
431 const DNSBrowserEvent
* inEvent
)
433 dns_service_discovery_ref obj
;
434 DNSServiceDomainEnumerationReply callback
;
437 DNS_UNUSED( inStatusCode
);
440 obj
= (dns_service_discovery_ref
) inContext
;
441 check( obj
->callback
);
442 callback
= (DNSServiceDomainEnumerationReply
) obj
->callback
;
444 switch( inEvent
->type
)
446 case kDNSBrowserEventTypeAddDomain
:
447 debugf( DEBUG_NAME
"add domain \"%s\"\n", inEvent
->data
.addDomain
.domain
);
451 callback( DNSServiceDomainEnumerationReplyAddDomain
, inEvent
->data
.addDomain
.domain
,
456 case kDNSBrowserEventTypeAddDefaultDomain
:
457 debugf( DEBUG_NAME
"add default domain \"%s\"\n", inEvent
->data
.addDefaultDomain
.domain
);
461 callback( DNSServiceDomainEnumerationReplyAddDomainDefault
, inEvent
->data
.addDefaultDomain
.domain
,
466 case kDNSBrowserEventTypeRemoveDomain
:
467 debugf( DEBUG_NAME
"add default domain \"%s\"\n", inEvent
->data
.removeDomain
.domain
);
471 callback( DNSServiceDomainEnumerationReplyRemoveDomain
, inEvent
->data
.removeDomain
.domain
,
481 //===========================================================================================================================
482 // DNSServiceBrowserCreate
483 //===========================================================================================================================
485 dns_service_discovery_ref
486 DNSServiceBrowserCreate(
488 const char * inDomain
,
489 DNSServiceBrowserReply inCallBack
,
493 dns_service_discovery_ref result
;
494 dns_service_discovery_ref obj
;
495 DNSBrowserRef browser
;
500 // Allocate and initialize the object.
502 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
503 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
505 obj
->type
= kDNSServiceDiscoveryObjectTypeBrowser
;
507 obj
->callback
= inCallBack
;
508 obj
->context
= inContext
;
510 // Create the underlying browser and start searching for domains.
512 err
= DNSBrowserCreate( 0, DNSServiceBrowserPrivateCallBack
, obj
, &browser
);
513 require_noerr( err
, exit
);
516 err
= DNSBrowserStartServiceSearch( browser
, 0, inType
, inDomain
);
517 require_noerr( err
, exit
);
528 DNSBrowserRelease( browser
, 0 );
532 DNSServiceDiscoveryDeallocate( obj
);
537 //===========================================================================================================================
538 // DNSServiceBrowserPrivateCallBack
539 //===========================================================================================================================
542 DNSServiceBrowserPrivateCallBack(
545 DNSStatus inStatusCode
,
546 const DNSBrowserEvent
* inEvent
)
548 dns_service_discovery_ref obj
;
549 DNSServiceBrowserReply callback
;
552 DNS_UNUSED( inStatusCode
);
555 obj
= (dns_service_discovery_ref
) inContext
;
556 check( obj
->callback
);
557 callback
= (DNSServiceBrowserReply
) obj
->callback
;
559 switch( inEvent
->type
)
561 case kDNSBrowserEventTypeAddService
:
562 debugf( DEBUG_NAME
"add service \"%s.%s%s\"\n",
563 inEvent
->data
.addService
.name
,
564 inEvent
->data
.addService
.type
,
565 inEvent
->data
.addService
.domain
);
569 callback( DNSServiceBrowserReplyAddInstance
,
570 inEvent
->data
.addService
.name
,
571 inEvent
->data
.addService
.type
,
572 inEvent
->data
.addService
.domain
,
578 case kDNSBrowserEventTypeRemoveService
:
579 debugf( DEBUG_NAME
"remove service \"%s.%s%s\"\n",
580 inEvent
->data
.removeService
.name
,
581 inEvent
->data
.removeService
.type
,
582 inEvent
->data
.removeService
.domain
);
586 callback( DNSServiceBrowserReplyRemoveInstance
,
587 inEvent
->data
.removeService
.name
,
588 inEvent
->data
.removeService
.type
,
589 inEvent
->data
.removeService
.domain
,
600 //===========================================================================================================================
601 // DNSServiceResolverResolve
602 //===========================================================================================================================
604 dns_service_discovery_ref
605 DNSServiceResolverResolve(
608 const char * inDomain
,
609 DNSServiceResolverReply inCallBack
,
613 dns_service_discovery_ref result
;
614 dns_service_discovery_ref obj
;
615 DNSResolverRef resolver
;
619 // Allocate and initialize the object.
621 obj
= (dns_service_discovery_ref
) malloc( sizeof( *obj
) );
622 require_action( obj
, exit
, err
= kDNSNoMemoryErr
);
624 obj
->type
= kDNSServiceDiscoveryObjectTypeResolver
;
626 obj
->callback
= inCallBack
;
627 obj
->context
= inContext
;
629 // Create the underlying resolver and start searching for domains.
631 err
= DNSResolverCreate( 0, inName
, inType
, inDomain
, DNSServiceResolverPrivateCallBack
, obj
, NULL
, &resolver
);
632 require_noerr( err
, exit
);
643 DNSServiceDiscoveryDeallocate( obj
);
648 //===========================================================================================================================
649 // DNSServiceResolverPrivateCallBack
650 //===========================================================================================================================
653 DNSServiceResolverPrivateCallBack(
655 DNSResolverRef inRef
,
656 DNSStatus inStatusCode
,
657 const DNSResolverEvent
* inEvent
)
659 dns_service_discovery_ref obj
;
660 DNSServiceResolverReply callback
;
661 struct sockaddr_in interfaceAddr
;
662 struct sockaddr_in addr
;
665 DNS_UNUSED( inStatusCode
);
668 obj
= (dns_service_discovery_ref
) inContext
;
669 check( obj
->callback
);
670 callback
= (DNSServiceResolverReply
) obj
->callback
;
672 switch( inEvent
->type
)
674 case kDNSResolverEventTypeResolved
:
675 debugf( DEBUG_NAME
"resolved \"%s.%s%s\"\n",
676 inEvent
->data
.resolved
.name
,
677 inEvent
->data
.resolved
.type
,
678 inEvent
->data
.resolved
.domain
);
680 memset( &interfaceAddr
, 0, sizeof( interfaceAddr
) );
681 interfaceAddr
.sin_family
= AF_INET
;
682 interfaceAddr
.sin_port
= 0;
683 interfaceAddr
.sin_addr
.s_addr
= inEvent
->data
.resolved
.interfaceIP
.u
.ipv4
.addr
.v32
;
685 memset( &addr
, 0, sizeof( addr
) );
686 addr
.sin_family
= AF_INET
;
687 addr
.sin_port
= inEvent
->data
.resolved
.address
.u
.ipv4
.port
.v16
;
688 addr
.sin_addr
.s_addr
= inEvent
->data
.resolved
.address
.u
.ipv4
.addr
.v32
;
692 callback( (struct sockaddr
*) &interfaceAddr
, (struct sockaddr
*) &addr
, inEvent
->data
.resolved
.textRecord
,
702 //===========================================================================================================================
703 // DNSServiceDiscoveryMachPort
704 //===========================================================================================================================
706 mach_port_t
DNSServiceDiscoveryMachPort( dns_service_discovery_ref inRef
)
710 debugf( DEBUG_NAME
"DNSServiceDiscoveryMachPort is not supported\n" );
714 //===========================================================================================================================
715 // DNSServiceDiscoveryDeallocate
716 //===========================================================================================================================
718 void DNSServiceDiscoveryDeallocate( dns_service_discovery_ref inRef
)
720 _dns_service_discovery_t
* obj
;
726 obj
= (_dns_service_discovery_t
*) inRef
;
729 case kDNSServiceDiscoveryObjectTypeRegistration
:
732 err
= DNSRegistrationRelease( (DNSRegistrationRef
) inRef
->ref
, 0 );
738 case kDNSServiceDiscoveryObjectTypeDomainEnumeration
:
741 err
= DNSBrowserRelease( (DNSBrowserRef
) inRef
->ref
, 0 );
747 case kDNSServiceDiscoveryObjectTypeBrowser
:
750 err
= DNSBrowserRelease( (DNSBrowserRef
) inRef
->ref
, 0 );
756 case kDNSServiceDiscoveryObjectTypeResolver
:
759 err
= DNSResolverRelease( (DNSResolverRef
) inRef
->ref
, 0 );
766 debugf( DEBUG_NAME
"unknown object type (%d)\n", obj
->type
);
771 //===========================================================================================================================
772 // DNSServiceDiscovery_handleReply
773 //===========================================================================================================================
775 void DNSServiceDiscovery_handleReply( void *inReplyMessage
)
777 DNS_UNUSED( inReplyMessage
);
779 debugf( DEBUG_NAME
"DNSServiceDiscovery_handleReply is not supported\n" );