]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/DNSServices/DNSServices.c
mDNSResponder-58.8.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / DNSServices / DNSServices.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
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.
44
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
47
48 Revision 1.13 2003/08/12 19:56:29 cheshire
49 Update to APSL 2.0
50
51 Revision 1.12 2003/07/23 00:00:04 cheshire
52 Add comments
53
54 Revision 1.11 2003/07/15 01:55:17 cheshire
55 <rdar://problem/3315777> Need to implement service registration with subtypes
56
57 Revision 1.10 2003/07/02 21:20:10 cheshire
58 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
59
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
65
66 Revision 1.8 2003/05/06 00:00:51 cheshire
67 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
68
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
72 Fixes:
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)
76
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")
79
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.)
84
85 Revision 1.4 2002/09/21 20:44:56 zarzycki
86 Added APSL info
87
88 Revision 1.3 2002/09/20 08:36:50 bradley
89 Fixed debug messages to output the correct information when resolving.
90
91 Revision 1.2 2002/09/20 05:58:01 bradley
92 DNS Services for Windows
93
94 */
95
96 #include <stddef.h>
97 #include <stdlib.h>
98 #include <string.h>
99
100 #if( __MACH__ )
101 #include <CoreServices/CoreServices.h>
102 #endif
103
104 #include "mDNSClientAPI.h"
105 #include "mDNSPlatformFunctions.h"
106
107 #include "DNSServices.h"
108
109 #ifdef __cplusplus
110 extern "C" {
111 #endif
112
113 #if 0
114 #pragma mark == Preprocessor ==
115 #endif
116
117 //===========================================================================================================================
118 // Preprocessor
119 //===========================================================================================================================
120
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.
124 #endif
125
126 #if 0
127 #pragma mark == Constants ==
128 #endif
129
130 //===========================================================================================================================
131 // Constants
132 //===========================================================================================================================
133
134 #define DEBUG_NAME "[DNSServices] "
135
136 enum
137 {
138 kDNSInitializeValidFlags = kDNSFlagAdvertise,
139
140 // Browser
141
142 kDNSBrowserCreateValidFlags = 0,
143 kDNSBrowserReleaseValidFlags = 0,
144 kDNSBrowserStartDomainSearchValidFlags = kDNSBrowserFlagRegistrationDomainsOnly,
145 kDNSBrowserStopDomainSearchValidFlags = 0,
146 kDNSBrowserStartServiceSearchValidFlags = kDNSBrowserFlagAutoResolve,
147 kDNSBrowserStopServiceSearchValidFlags = 0,
148
149 // Resolver
150
151 kDNSResolverCreateValidFlags = kDNSResolverFlagOneShot |
152 kDNSResolverFlagOnlyIfUnique |
153 kDNSResolverFlagAutoReleaseByName,
154 kDNSResolverReleaseValidFlags = 0,
155
156 // Service Registration
157
158 kDNSRegistrationCreateValidFlags = kDNSRegistrationFlagPreFormattedTextRecord |
159 kDNSRegistrationFlagAutoRenameOnConflict,
160 kDNSNoSuchServiceRegistrationCreateValidFlags = 0,
161 kDNSRegistrationReleaseValidFlags = 0,
162 kDNSRegistrationUpdateValidFlags = 0,
163
164 kDNSRegistrationFlagPrivateNoSuchService = ( 1 << 16 ),
165
166 // Domain Registration
167
168 kDNSDomainRegistrationCreateValidFlags = 0,
169 kDNSDomainRegistrationReleaseValidFlags = 0,
170
171 // Host Registration
172
173 kDNSHostRegistrationCreateValidFlags = kDNSHostRegistrationFlagOnlyIfNotFound |
174 kDNSHostRegistrationFlagAutoRenameOnConflict,
175 kDNSHostRegistrationReleaseValidFlags = 0
176 };
177
178 #define kDNSCountCacheEntryCountDefault 64
179
180 #if 0
181 #pragma mark == Structures ==
182 #endif
183
184 //===========================================================================================================================
185 // Structures
186 //===========================================================================================================================
187
188 // Browser
189
190 typedef struct DNSBrowser DNSBrowser;
191 struct DNSBrowser
192 {
193 DNSBrowser * next;
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 ];
206 };
207
208 // Resolver
209
210 typedef struct DNSResolver DNSResolver;
211 struct DNSResolver
212 {
213 DNSResolver * next;
214 DNSResolverFlags flags;
215 DNSResolverCallBack callback;
216 void * callbackContext;
217 DNSBrowserRef owner;
218 ServiceInfoQuery query;
219 ServiceInfo info;
220 mDNSBool isResolving;
221 char resolveName[ 256 ];
222 char resolveType[ 256 ];
223 char resolveDomain[ 256 ];
224 };
225
226 // Registration
227
228 typedef struct DNSRegistration DNSRegistration;
229 struct DNSRegistration
230 {
231 DNSRegistration * next;
232 DNSRegistrationFlags flags;
233 DNSRegistrationCallBack callback;
234 void * callbackContext;
235 char interfaceName[ 256 ];
236 ServiceRecordSet set;
237
238 // WARNING: Do not add fields after the ServiceRecordSet. This is where oversized TXT record space is allocated.
239 };
240
241 // Domain Registration
242
243 typedef struct DNSDomainRegistration DNSDomainRegistration;
244 struct DNSDomainRegistration
245 {
246 DNSDomainRegistration * next;
247 DNSDomainRegistrationFlags flags;
248 AuthRecord rr;
249 };
250
251 // Domain Registration
252
253 typedef struct DNSHostRegistration DNSHostRegistration;
254 struct DNSHostRegistration
255 {
256 DNSHostRegistration * next;
257 domainlabel name;
258 domainlabel domain;
259 long refCount;
260 DNSHostRegistrationCallBack callback;
261 void * callbackContext;
262 DNSHostRegistrationFlags flags;
263 char interfaceName[ 256 ];
264 AuthRecord RR_A;
265 AuthRecord RR_PTR;
266 };
267
268 #if 0
269 #pragma mark == Macros ==
270 #endif
271
272 //===========================================================================================================================
273 // Macros
274 //===========================================================================================================================
275
276 // Emulate Mac OS debugging macros for non-Mac platforms.
277
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)
290 #endif
291
292 #define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
293
294 #if 0
295 #pragma mark == Prototypes ==
296 #endif
297
298 //===========================================================================================================================
299 // Prototypes
300 //===========================================================================================================================
301
302 // General
303
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 );
308
309 // Browser
310
311 mDNSlocal void
312 DNSBrowserPrivateCallBack(
313 mDNS * const inMDNS,
314 DNSQuestion * inQuestion,
315 const ResourceRecord * const inAnswer,
316 mDNSBool inAddRecord );
317
318 mDNSlocal void
319 DNSBrowserPrivateResolverCallBack(
320 void * inContext,
321 DNSResolverRef inRef,
322 DNSStatus inStatusCode,
323 const DNSResolverEvent * inEvent );
324
325 mDNSlocal DNSBrowserRef DNSBrowserFindObject( DNSBrowserRef inRef );
326 mDNSlocal DNSBrowserRef DNSBrowserRemoveObject( DNSBrowserRef inRef );
327
328 // Resolver
329
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 );
336
337 // Registration
338
339 mDNSlocal void
340 DNSRegistrationPrivateCallBack(
341 mDNS * const inMDNS,
342 ServiceRecordSet * const inSet,
343 mStatus inResult );
344
345 mDNSlocal void
346 DNSNoSuchServiceRegistrationPrivateCallBack(
347 mDNS * const inMDNS,
348 AuthRecord * const inRR,
349 mStatus inResult );
350
351 mDNSlocal void DNSRegistrationUpdateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldData );
352
353 mDNSlocal DNSRegistrationRef * DNSRegistrationFindObject( DNSRegistrationRef inRef );
354 mDNSlocal DNSRegistrationRef DNSRegistrationRemoveObject( DNSRegistrationRef inRef );
355
356 // Domain Registration
357
358 mDNSlocal DNSDomainRegistrationRef DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef );
359
360 // Host Registration
361
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 );
365
366 // Utilities
367
368 mDNSlocal DNSStatus DNSMemAlloc( size_t inSize, void *outMem );
369 mDNSlocal void DNSMemFree( void *inMem );
370 mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, DNSNetworkAddress *outAddr );
371
372 // Platform Accessors
373
374 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
375 struct mDNSPlatformInterfaceInfo
376 {
377 const char * name;
378 mDNSAddr ip;
379 };
380
381 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
382 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
383
384 #if 0
385 #pragma mark == Globals ==
386 #endif
387
388 //===========================================================================================================================
389 // Globals
390 //===========================================================================================================================
391
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;
400
401 #if 0
402 #pragma mark -
403 #pragma mark == General ==
404 #endif
405
406 //===========================================================================================================================
407 // DNSServicesInitialize
408 //===========================================================================================================================
409
410 DNSStatus DNSServicesInitialize( DNSFlags inFlags, DNSCount inCacheEntryCount )
411 {
412 DNSStatus err;
413 mDNSBool advertise;
414
415 require_action( ( inFlags & ~kDNSInitializeValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
416
417 // Allocate the record cache.
418
419 if( inCacheEntryCount == 0 )
420 {
421 inCacheEntryCount = kDNSCountCacheEntryCountDefault;
422 }
423 gMDNSCache = (CacheRecord *) malloc( inCacheEntryCount * sizeof( *gMDNSCache ) );
424 require_action( gMDNSCache, exit, err = kDNSNoMemoryErr );
425
426 // Initialize mDNS.
427
428 if( inFlags & kDNSFlagAdvertise )
429 {
430 advertise = mDNS_Init_AdvertiseLocalAddresses;
431 }
432 else
433 {
434 advertise = mDNS_Init_DontAdvertiseLocalAddresses;
435 }
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 );
440
441 gMDNSPtr = &gMDNS;
442
443 exit:
444 if( err )
445 {
446 DNSServicesFinalize();
447 }
448 return( err );
449 }
450
451 //===========================================================================================================================
452 // DNSServicesFinalize
453 //===========================================================================================================================
454
455 void DNSServicesFinalize( void )
456 {
457 if( gMDNSPtr )
458 {
459 mDNSPlatformLock( &gMDNS );
460
461 // Clean up any dangling service registrations.
462
463 while( gDNSRegistrationList )
464 {
465 DNSRegistrationRef serviceRef;
466
467 serviceRef = gDNSRegistrationList;
468 DNSRegistrationRelease( serviceRef, 0UL );
469 check_string( serviceRef != gDNSRegistrationList, "dangling service registration cannot be cleaned up" );
470 }
471
472 // Clean up any dangling domain registrations.
473
474 while( gDNSDomainRegistrationList )
475 {
476 DNSDomainRegistrationRef domainRef;
477
478 domainRef = gDNSDomainRegistrationList;
479 DNSDomainRegistrationRelease( domainRef, 0 );
480 check_string( domainRef != gDNSDomainRegistrationList, "dangling domain registration cannot be cleaned up" );
481 }
482
483 // Clean up any dangling host registrations.
484
485 while( gDNSHostRegistrationList )
486 {
487 DNSHostRegistrationRef hostRef;
488 long refCount;
489
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" );
495 }
496
497 // Clean up any dangling browsers.
498
499 while( gDNSBrowserList )
500 {
501 DNSBrowserRef browserRef;
502
503 browserRef = gDNSBrowserList;
504 DNSBrowserRelease( browserRef, 0 );
505 check_string( browserRef != gDNSBrowserList, "dangling browser cannot be cleaned up" );
506 }
507
508 // Clean up any dangling resolvers.
509
510 while( gDNSResolverList )
511 {
512 DNSResolverRef resolverRef;
513
514 resolverRef = gDNSResolverList;
515 DNSResolverRelease( resolverRef, 0 );
516 check_string( resolverRef != gDNSResolverList, "dangling resolver cannot be cleaned up" );
517 }
518
519 // Null out our MDNS ptr before releasing the lock so no other threads can sneak in and start operations.
520
521 gMDNSPtr = mDNSNULL;
522 mDNSPlatformUnlock( &gMDNS );
523
524 // Tear down mDNS.
525
526 mDNS_Close( &gMDNS );
527 }
528 if( gMDNSCache )
529 {
530 free( gMDNSCache );
531 gMDNSCache = mDNSNULL;
532 }
533 }
534
535 //===========================================================================================================================
536 // DNSServicesLock
537 //===========================================================================================================================
538
539 mDNSlocal void DNSServicesLock( void )
540 {
541 if( gMDNSPtr )
542 {
543 mDNSPlatformLock( gMDNSPtr );
544 }
545 }
546
547 //===========================================================================================================================
548 // DNSServicesUnlock
549 //===========================================================================================================================
550
551 mDNSlocal void DNSServicesUnlock( void )
552 {
553 if( gMDNSPtr )
554 {
555 mDNSPlatformUnlock( gMDNSPtr );
556 }
557 }
558
559 //===========================================================================================================================
560 // DNSServicesMDNSCallBack
561 //===========================================================================================================================
562
563 mDNSlocal void DNSServicesMDNSCallBack( mDNS *const inMDNS, mStatus inStatus )
564 {
565 DNS_UNUSED( inMDNS );
566 DNS_UNUSED( inStatus );
567 check( inMDNS );
568
569 debugf( DEBUG_NAME "MDNS callback (status=%ld)", inStatus );
570
571 if( inStatus == mStatus_ConfigChanged )
572 {
573 DNSServicesUpdateInterfaceSpecificObjects( inMDNS );
574 }
575 }
576
577 //===========================================================================================================================
578 // DNSServicesUpdateInterfaceSpecificObjects
579 //===========================================================================================================================
580
581 mDNSlocal void DNSServicesUpdateInterfaceSpecificObjects( mDNS *const inMDNS )
582 {
583 DNSRegistration * serviceRegistration;
584
585 DNSServicesLock();
586
587 // Update interface-specific service registrations.
588
589 for( serviceRegistration = gDNSRegistrationList; serviceRegistration; serviceRegistration = serviceRegistration->next )
590 {
591 if( serviceRegistration->interfaceName[ 0 ] != '\0' )
592 {
593 mStatus err;
594 mDNSInterfaceID interfaceID;
595
596 err = mDNSPlatformInterfaceNameToID( inMDNS, serviceRegistration->interfaceName, &interfaceID );
597 check_noerr( err );
598 if( err == mStatus_NoError )
599 {
600 // Update all the resource records with the new interface ID.
601
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;
606 }
607 }
608 }
609
610 DNSServicesUnlock();
611 }
612
613 #if 0
614 #pragma mark -
615 #pragma mark == Browser ==
616 #endif
617
618 //===========================================================================================================================
619 // DNSBrowserCreate
620 //===========================================================================================================================
621
622 DNSStatus
623 DNSBrowserCreate(
624 DNSBrowserFlags inFlags,
625 DNSBrowserCallBack inCallBack,
626 void * inCallBackContext,
627 DNSBrowserRef * outRef )
628 {
629 DNSStatus err;
630 DNSBrowser * objectPtr;
631
632 DNSServicesLock();
633 require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
634 require_action( ( inFlags & ~kDNSBrowserCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
635 require_action( inCallBack, exit, err = kDNSBadParamErr );
636
637 // Allocate the object and set it up.
638
639 err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
640 require_noerr( err, exit );
641 memset( objectPtr, 0, sizeof( *objectPtr ) );
642
643 objectPtr->flags = inFlags;
644 objectPtr->callback = inCallBack;
645 objectPtr->callbackContext = inCallBackContext;
646
647 // Add the object to the list.
648
649 objectPtr->next = gDNSBrowserList;
650 gDNSBrowserList = objectPtr;
651
652 if( outRef )
653 {
654 *outRef = objectPtr;
655 }
656
657 exit:
658 DNSServicesUnlock();
659 return( err );
660 }
661
662 //===========================================================================================================================
663 // DNSBrowserRelease
664 //===========================================================================================================================
665
666 DNSStatus DNSBrowserRelease( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
667 {
668 DNSStatus err;
669 DNSBrowserEvent event;
670
671 DNSServicesLock();
672 require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
673 require_action( inRef, exit, err = kDNSBadReferenceErr );
674 require_action( ( inFlags & ~kDNSBrowserReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
675
676 // Stop service and domain browsing and remove any resolvers dependent on this browser.
677
678 DNSBrowserStopDomainSearch( inRef, 0 );
679 DNSBrowserStopServiceSearch( inRef, 0 );
680 DNSResolverRemoveDependentByBrowser( inRef );
681
682 // Remove the object from the list.
683
684 inRef = DNSBrowserRemoveObject( inRef );
685 require_action( inRef, exit, err = kDNSBadReferenceErr );
686
687 // Call the callback with a release event.
688
689 check( inRef->callback );
690 memset( &event, 0, sizeof( event ) );
691 event.type = kDNSBrowserEventTypeRelease;
692 inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
693
694 // Release the memory used by the object.
695
696 DNSMemFree( inRef );
697 err = kDNSNoErr;
698
699 exit:
700 DNSServicesUnlock();
701 return( err );
702 }
703
704 //===========================================================================================================================
705 // DNSBrowserStartDomainSearch
706 //===========================================================================================================================
707
708 DNSStatus DNSBrowserStartDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
709 {
710 DNSStatus err;
711 mDNS_DomainType type;
712 mDNS_DomainType defaultType;
713 DNSBrowserEvent event;
714 mDNSBool isDomainBrowsing;
715
716 isDomainBrowsing = mDNSfalse;
717
718 DNSServicesLock();
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 );
723
724 // Determine whether to browse for normal domains or registration domains.
725
726 if( inFlags & kDNSBrowserFlagRegistrationDomainsOnly )
727 {
728 type = mDNS_DomainTypeRegistration;
729 defaultType = mDNS_DomainTypeRegistrationDefault;
730 }
731 else
732 {
733 type = mDNS_DomainTypeBrowse;
734 defaultType = mDNS_DomainTypeBrowseDefault;
735 }
736
737 // Start the browse operations.
738
739 err = mDNS_GetDomains( gMDNSPtr, &inRef->domainQuestion, type, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
740 require_noerr( err, exit );
741 isDomainBrowsing = mDNStrue;
742
743 err = mDNS_GetDomains( gMDNSPtr, &inRef->defaultDomainQuestion, defaultType, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
744 require_noerr( err, exit );
745
746 inRef->domainSearchFlags = inFlags;
747 inRef->isDomainBrowsing = mDNStrue;
748
749 // Call back immediately with "local." since that is always available for all types of browsing.
750
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 );
756
757 exit:
758 if( err && isDomainBrowsing )
759 {
760 mDNS_StopGetDomains( gMDNSPtr, &inRef->domainQuestion );
761 }
762 DNSServicesUnlock();
763 return( err );
764 }
765
766 //===========================================================================================================================
767 // DNSBrowserStopDomainSearch
768 //===========================================================================================================================
769
770 DNSStatus DNSBrowserStopDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
771 {
772 DNSStatus err;
773
774 DNSServicesLock();
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 )
779 {
780 err = kDNSBadStateErr;
781 goto exit;
782 }
783
784 // Stop the browse operations.
785
786 mDNS_StopGetDomains( gMDNSPtr, &inRef->defaultDomainQuestion );
787 mDNS_StopGetDomains( gMDNSPtr, &inRef->domainQuestion );
788 inRef->isDomainBrowsing = mDNSfalse;
789 err = kDNSNoErr;
790
791 exit:
792 DNSServicesUnlock();
793 return( err );
794 }
795
796 //===========================================================================================================================
797 // DNSBrowserStartServiceSearch
798 //===========================================================================================================================
799
800 DNSStatus
801 DNSBrowserStartServiceSearch(
802 DNSBrowserRef inRef,
803 DNSBrowserFlags inFlags,
804 const char * inType,
805 const char * inDomain )
806 {
807 DNSStatus err;
808 domainname type;
809 domainname domain;
810
811 DNSServicesLock();
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 );
817
818 // Default to the local domain when null is passed in.
819
820 if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
821 {
822 inDomain = kDNSLocalDomain;
823 }
824
825 // Save off the search criteria (in case it needs to be automatically restarted later).
826
827 inRef->serviceSearchFlags = inFlags;
828
829 strncpy( inRef->searchServiceType, inType, sizeof( inRef->searchServiceType ) - 1 );
830 inRef->searchServiceType[ sizeof( inRef->searchServiceType ) - 1 ] = '\0';
831
832 strncpy( inRef->searchDomain, inDomain, sizeof( inRef->searchDomain ) - 1 );
833 inRef->searchDomain[ sizeof( inRef->searchDomain ) - 1 ] = '\0';
834
835 // Start the browse operation with mDNS using our private callback.
836
837 MakeDomainNameFromDNSNameString( &type, inType );
838 MakeDomainNameFromDNSNameString( &domain, inDomain );
839
840 err = mDNS_StartBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion, &type, &domain, mDNSInterface_Any,
841 DNSBrowserPrivateCallBack, inRef );
842 require_noerr( err, exit );
843
844 inRef->isServiceBrowsing = mDNStrue;
845
846 exit:
847 DNSServicesUnlock();
848 return( err );
849 }
850
851 //===========================================================================================================================
852 // DNSBrowserStopServiceSearch
853 //===========================================================================================================================
854
855 DNSStatus DNSBrowserStopServiceSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
856 {
857 DNSStatus err;
858
859 DNSServicesLock();
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 )
864 {
865 err = kDNSBadStateErr;
866 goto exit;
867 }
868
869 // Stop the browse operation with mDNS. Remove any resolvers dependent on browser since we are no longer searching.
870
871 mDNS_StopBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion );
872 DNSResolverRemoveDependentByBrowser( inRef );
873 inRef->isServiceBrowsing = mDNSfalse;
874 err = kDNSNoErr;
875
876 exit:
877 DNSServicesUnlock();
878 return( err );
879 }
880
881 //===========================================================================================================================
882 // DNSBrowserPrivateCallBack
883 //===========================================================================================================================
884
885 mDNSlocal void
886 DNSBrowserPrivateCallBack(
887 mDNS * const inMDNS,
888 DNSQuestion * inQuestion,
889 const ResourceRecord * const inAnswer,
890 mDNSBool inAddRecord )
891 {
892 DNSBrowserRef objectPtr;
893 domainlabel name;
894 domainname type;
895 domainname domain;
896 char nameString[ 256 ];
897 char typeString[ 256 ];
898 char domainString[ 256 ];
899 DNSBrowserEvent event;
900 mStatus err;
901
902 check( inMDNS );
903 check( inQuestion );
904 check( inAnswer );
905
906 DNSServicesLock();
907
908 // Exclude non-PTR answers.
909
910 require( inAnswer->rrtype == kDNSType_PTR, exit );
911
912 // Exit if object is no longer valid. Should never happen.
913
914 objectPtr = DNSBrowserFindObject( (DNSBrowserRef) inQuestion->QuestionContext );
915 require( objectPtr, exit );
916
917 // Determine what type of callback it is based on the question.
918
919 memset( &event, 0, sizeof( event ) );
920 if( inQuestion == &objectPtr->serviceBrowseQuestion )
921 {
922 DNSBrowserEventServiceData * serviceDataPtr;
923 DNSBrowserFlags browserFlags;
924
925 // Extract name, type, and domain from the resource record.
926
927 DeconstructServiceName( &inAnswer->rdata->u.name, &name, &type, &domain );
928 ConvertDomainLabelToCString_unescaped( &name, nameString );
929 ConvertDomainNameToCString( &type, typeString );
930 ConvertDomainNameToCString( &domain, domainString );
931
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.
934
935 if( !inAddRecord )
936 {
937 DNSResolverRemoveDependentByName( &inAnswer->rdata->u.name );
938
939 event.type = kDNSBrowserEventTypeRemoveService;
940 serviceDataPtr = &event.data.removeService;
941 }
942 else
943 {
944 event.type = kDNSBrowserEventTypeAddService;
945 serviceDataPtr = &event.data.addService;
946 }
947 serviceDataPtr->interfaceName = "";
948 if( inAnswer->InterfaceID != mDNSInterface_Any )
949 {
950 mDNSPlatformInterfaceInfo info;
951
952 err = mDNSPlatformInterfaceIDToInfo( inMDNS, inAnswer->InterfaceID, &info );
953 if( err == mStatus_NoError )
954 {
955 serviceDataPtr->interfaceName = info.name;
956 MDNSAddrToDNSAddress( &info.ip, &serviceDataPtr->interfaceIP );
957 }
958 else
959 {
960 serviceDataPtr->interfaceName = "";
961 }
962 }
963 serviceDataPtr->interfaceID = inAnswer->InterfaceID;
964 serviceDataPtr->name = nameString;
965 serviceDataPtr->type = typeString;
966 serviceDataPtr->domain = domainString;
967 serviceDataPtr->flags = 0;
968
969 // Call the callback.
970
971 browserFlags = objectPtr->serviceSearchFlags;
972 objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
973
974 // Automatically resolve newly discovered names if the auto-resolve option is enabled.
975
976 if( ( browserFlags & kDNSBrowserFlagAutoResolve ) && inAddRecord )
977 {
978 DNSStatus err;
979 DNSResolverFlags flags;
980
981 flags = kDNSResolverFlagOnlyIfUnique | kDNSResolverFlagAutoReleaseByName;
982 err = DNSResolverCreate( flags, nameString, typeString, domainString, DNSBrowserPrivateResolverCallBack,
983 mDNSNULL, objectPtr, mDNSNULL );
984 check_noerr( err );
985 }
986 }
987 else
988 {
989 DNSBrowserEventDomainData * domainDataPtr;
990
991 // Determine the event type. A TTL of zero means the domain is no longer available.
992
993 domainDataPtr = mDNSNULL;
994 if( inQuestion == &objectPtr->domainQuestion )
995 {
996 if( !inAddRecord )
997 {
998 event.type = kDNSBrowserEventTypeRemoveDomain;
999 domainDataPtr = &event.data.removeDomain;
1000 }
1001 else
1002 {
1003 event.type = kDNSBrowserEventTypeAddDomain;
1004 domainDataPtr = &event.data.addDomain;
1005 }
1006 }
1007 else if( inQuestion == &objectPtr->defaultDomainQuestion )
1008 {
1009 if( !inAddRecord )
1010 {
1011 event.type = kDNSBrowserEventTypeRemoveDomain;
1012 domainDataPtr = &event.data.removeDomain;
1013 }
1014 else
1015 {
1016 event.type = kDNSBrowserEventTypeAddDefaultDomain;
1017 domainDataPtr = &event.data.addDefaultDomain;
1018 }
1019 }
1020 require_string( domainDataPtr, exit, "domain response for unknown question" );
1021
1022 // Extract domain name from the resource record and fill in the event data.
1023
1024 ConvertDomainNameToCString( &inAnswer->rdata->u.name, domainString );
1025
1026 domainDataPtr->interfaceName = "";
1027 if( inAnswer->InterfaceID != mDNSInterface_Any )
1028 {
1029 mDNSPlatformInterfaceInfo info;
1030
1031 err = mDNSPlatformInterfaceIDToInfo( inMDNS, inAnswer->InterfaceID, &info );
1032 if( err == mStatus_NoError )
1033 {
1034 domainDataPtr->interfaceName = info.name;
1035 MDNSAddrToDNSAddress( &info.ip, &domainDataPtr->interfaceIP );
1036 }
1037 else
1038 {
1039 domainDataPtr->interfaceName = "";
1040 }
1041 }
1042 domainDataPtr->interfaceID = inAnswer->InterfaceID;
1043 domainDataPtr->domain = domainString;
1044 domainDataPtr->flags = 0;
1045
1046 // Call the callback.
1047
1048 objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
1049 }
1050
1051 exit:
1052 DNSServicesUnlock();
1053 }
1054
1055 //===========================================================================================================================
1056 // DNSBrowserPrivateResolverCallBack
1057 //===========================================================================================================================
1058
1059 mDNSlocal void
1060 DNSBrowserPrivateResolverCallBack(
1061 void * inContext,
1062 DNSResolverRef inRef,
1063 DNSStatus inStatusCode,
1064 const DNSResolverEvent * inEvent )
1065 {
1066 DNSBrowserRef objectPtr;
1067 DNSBrowserEvent event;
1068
1069 DNS_UNUSED( inContext );
1070 DNS_UNUSED( inStatusCode );
1071
1072 DNSServicesLock();
1073
1074 // Exit if object is no longer valid. Should never happen.
1075
1076 objectPtr = inRef->owner;
1077 require( objectPtr, exit );
1078
1079 switch( inEvent->type )
1080 {
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 );
1091
1092 // Re-package the resolver event as a browser event and call the callback.
1093
1094 memset( &event, 0, sizeof( event ) );
1095 event.type = kDNSBrowserEventTypeResolved;
1096 event.data.resolved = &inEvent->data.resolved;
1097
1098 objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
1099 break;
1100
1101 case kDNSResolverEventTypeRelease:
1102 verbosedebugf( DEBUG_NAME "private resolver callback: release (ref=0x%08X)", inRef );
1103 break;
1104
1105 default:
1106 verbosedebugf( DEBUG_NAME "private resolver callback: unknown event (ref=0x%08X, event=%ld)", inRef, inEvent->type );
1107 break;
1108 }
1109
1110 exit:
1111 DNSServicesUnlock();
1112 }
1113
1114 //===========================================================================================================================
1115 // DNSBrowserFindObject
1116 //
1117 // Warning: Assumes the DNS lock is held.
1118 //===========================================================================================================================
1119
1120 mDNSlocal DNSBrowserRef DNSBrowserFindObject( DNSBrowserRef inRef )
1121 {
1122 DNSBrowser * p;
1123
1124 check( inRef );
1125
1126 // Find the object in the list.
1127
1128 for( p = gDNSBrowserList; p; p = p->next )
1129 {
1130 if( p == inRef )
1131 {
1132 break;
1133 }
1134 }
1135 return( p );
1136 }
1137
1138 //===========================================================================================================================
1139 // DNSBrowserRemoveObject
1140 //
1141 // Warning: Assumes the DNS lock is held.
1142 //===========================================================================================================================
1143
1144 mDNSlocal DNSBrowserRef DNSBrowserRemoveObject( DNSBrowserRef inRef )
1145 {
1146 DNSBrowser ** p;
1147 DNSBrowser * found;
1148
1149 for( p = &gDNSBrowserList; *p; p = &( *p )->next )
1150 {
1151 if( *p == inRef )
1152 {
1153 break;
1154 }
1155 }
1156 found = *p;
1157 if( found )
1158 {
1159 *p = found->next;
1160 }
1161 return( found );
1162 }
1163
1164 #if 0
1165 #pragma mark -
1166 #pragma mark == Resolver ==
1167 #endif
1168
1169 //===========================================================================================================================
1170 // DNSResolverCreate
1171 //===========================================================================================================================
1172
1173 DNSStatus
1174 DNSResolverCreate(
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 )
1183 {
1184 DNSStatus err;
1185 int isAutoRelease;
1186 DNSResolver * objectPtr;
1187 domainlabel name;
1188 domainname type;
1189 domainname domain;
1190 domainname fullName;
1191
1192 objectPtr = mDNSNULL;
1193
1194 // Check parameters.
1195
1196 DNSServicesLock();
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 );
1206
1207 // Convert and package up the name, type, and domain into a single fully-qualified domain name to resolve.
1208
1209 MakeDomainLabelFromLiteralString( &name, inName );
1210 MakeDomainNameFromDNSNameString( &type, inType );
1211 MakeDomainNameFromDNSNameString( &domain, inDomain );
1212 ConstructServiceName( &fullName, &name, &type, &domain );
1213
1214 // If the caller only wants to add unique resolvers, check if a resolver for this name is already present.
1215
1216 if( inFlags & kDNSResolverFlagOnlyIfUnique )
1217 {
1218 if( DNSResolverFindObjectByName( &fullName ) )
1219 {
1220 if( outRef )
1221 {
1222 *outRef = mDNSNULL;
1223 }
1224 err = kDNSNoErr;
1225 goto exit;
1226 }
1227 }
1228
1229 // Allocate the object and set it up.
1230
1231 err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
1232 require_noerr( err, exit );
1233 memset( objectPtr, 0, sizeof( *objectPtr ) );
1234
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;
1241
1242 // Save off the resolve info so the callback can get it.
1243
1244 strncpy( objectPtr->resolveName, inName, sizeof( objectPtr->resolveName ) - 1 );
1245 objectPtr->resolveName[ sizeof( objectPtr->resolveName ) - 1 ] = '\0';
1246
1247 strncpy( objectPtr->resolveType, inType, sizeof( objectPtr->resolveType ) - 1 );
1248 objectPtr->resolveType[ sizeof( objectPtr->resolveType ) - 1 ] = '\0';
1249
1250 strncpy( objectPtr->resolveDomain, inDomain, sizeof( objectPtr->resolveDomain ) - 1 );
1251 objectPtr->resolveDomain[ sizeof( objectPtr->resolveDomain ) - 1 ] = '\0';
1252
1253 // Add the object to the list.
1254
1255 objectPtr->next = gDNSResolverList;
1256 gDNSResolverList = objectPtr;
1257
1258 // Start the resolving process.
1259
1260 objectPtr->isResolving = mDNStrue;
1261 err = mDNS_StartResolveService( gMDNSPtr, &objectPtr->query, &objectPtr->info, DNSResolverPrivateCallBack, objectPtr );
1262 require_noerr( err, exit );
1263
1264 if( outRef )
1265 {
1266 *outRef = objectPtr;
1267 }
1268
1269 exit:
1270 if( err && objectPtr )
1271 {
1272 DNSResolverRemoveObject( objectPtr );
1273 DNSMemFree( objectPtr );
1274 }
1275 DNSServicesUnlock();
1276 return( err );
1277 }
1278
1279 //===========================================================================================================================
1280 // DNSResolverRelease
1281 //===========================================================================================================================
1282
1283 DNSStatus DNSResolverRelease( DNSResolverRef inRef, DNSResolverFlags inFlags )
1284 {
1285 DNSStatus err;
1286 DNSResolverEvent event;
1287
1288 DNSServicesLock();
1289 require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
1290 require_action( ( inFlags & ~kDNSResolverReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
1291
1292 // Remove the object from the list.
1293
1294 inRef = DNSResolverRemoveObject( inRef );
1295 require_action( inRef, exit, err = kDNSBadReferenceErr );
1296
1297 // Stop the resolving process.
1298
1299 if( inRef->isResolving )
1300 {
1301 inRef->isResolving = mDNSfalse;
1302 mDNS_StopResolveService( gMDNSPtr, &inRef->query );
1303 }
1304
1305 // Call the callback with a release event.
1306
1307 check( inRef->callback );
1308 memset( &event, 0, sizeof( event ) );
1309 event.type = kDNSResolverEventTypeRelease;
1310 inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
1311
1312 // Release the memory used by the object.
1313
1314 DNSMemFree( inRef );
1315 err = kDNSNoErr;
1316
1317 exit:
1318 DNSServicesUnlock();
1319 return( err );
1320 }
1321
1322 //===========================================================================================================================
1323 // DNSResolverFindObject
1324 //
1325 // Warning: Assumes the DNS lock is held.
1326 //===========================================================================================================================
1327
1328 mDNSlocal DNSResolverRef DNSResolverFindObject( DNSResolverRef inRef )
1329 {
1330 DNSResolver * p;
1331
1332 check( inRef );
1333
1334 // Find the object in the list.
1335
1336 for( p = gDNSResolverList; p; p = p->next )
1337 {
1338 if( p == inRef )
1339 {
1340 break;
1341 }
1342 }
1343 return( p );
1344 }
1345
1346 //===========================================================================================================================
1347 // DNSResolverFindObjectByName
1348 //
1349 // Warning: Assumes the DNS lock is held.
1350 //===========================================================================================================================
1351
1352 mDNSlocal DNSResolverRef DNSResolverFindObjectByName( const domainname *inName )
1353 {
1354 DNSResolver * p;
1355
1356 check( inName );
1357
1358 for( p = gDNSResolverList; p; p = p->next )
1359 {
1360 if( SameDomainName( &p->info.name, inName ) )
1361 {
1362 break;
1363 }
1364 }
1365 return( p );
1366 }
1367
1368 //===========================================================================================================================
1369 // DNSResolverPrivateCallBack
1370 //===========================================================================================================================
1371
1372 mDNSlocal void DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery *inQuery )
1373 {
1374 DNSResolverRef objectPtr;
1375 DNSResolverEvent event;
1376 char * txtString;
1377 mStatus err;
1378 mDNSBool release;
1379
1380 txtString = NULL;
1381
1382 DNSServicesLock();
1383
1384 // Exit if object is no longer valid. Should never happen.
1385
1386 objectPtr = DNSResolverFindObject( (DNSResolverRef) inQuery->ServiceInfoQueryContext );
1387 require( objectPtr, exit );
1388
1389 // Convert the raw TXT record into a null-terminated string with \001-delimited records for Mac OS X-style clients.
1390
1391 err = DNSTextRecordEscape( inQuery->info->TXTinfo, inQuery->info->TXTlen, &txtString );
1392 check_noerr( err );
1393
1394 // Package up the results and call the callback.
1395
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 )
1403 {
1404 mDNSPlatformInterfaceInfo info;
1405
1406 err = mDNSPlatformInterfaceIDToInfo( inMDNS, inQuery->info->InterfaceID, &info );
1407 if( err == mStatus_NoError )
1408 {
1409 event.data.resolved.interfaceName = info.name;
1410 MDNSAddrToDNSAddress( &info.ip, &event.data.resolved.interfaceIP );
1411 }
1412 else
1413 {
1414 event.data.resolved.interfaceName = "";
1415 }
1416 }
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 );
1427
1428 // Auto-release the object if needed.
1429
1430 if( release )
1431 {
1432 DNSResolverRelease( objectPtr, 0 );
1433 }
1434
1435 exit:
1436 DNSServicesUnlock();
1437 if( txtString )
1438 {
1439 free( txtString );
1440 }
1441 }
1442
1443 //===========================================================================================================================
1444 // DNSResolverRemoveObject
1445 //
1446 // Warning: Assumes the DNS lock is held.
1447 //===========================================================================================================================
1448
1449 mDNSlocal DNSResolverRef DNSResolverRemoveObject( DNSResolverRef inRef )
1450 {
1451 DNSResolver ** p;
1452 DNSResolver * found;
1453
1454 for( p = &gDNSResolverList; *p; p = &( *p )->next )
1455 {
1456 if( *p == inRef )
1457 {
1458 break;
1459 }
1460 }
1461 found = *p;
1462 if( found )
1463 {
1464 *p = found->next;
1465 }
1466 return( found );
1467 }
1468
1469 //===========================================================================================================================
1470 // DNSResolverRemoveDependentByBrowser
1471 //
1472 // Warning: Assumes the DNS lock is held.
1473 //===========================================================================================================================
1474
1475 mDNSlocal void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef )
1476 {
1477 DNSResolver * p;
1478
1479 check( inBrowserRef );
1480
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.
1483
1484 do
1485 {
1486 for( p = gDNSResolverList; p; p = p->next )
1487 {
1488 if( p->owner == inBrowserRef )
1489 {
1490 DNSResolverRelease( p, 0 );
1491 break;
1492 }
1493 }
1494
1495 } while( p );
1496 }
1497
1498 //===========================================================================================================================
1499 // DNSResolverRemoveDependentByName
1500 //
1501 // Warning: Assumes the DNS lock is held.
1502 //===========================================================================================================================
1503
1504 mDNSlocal void DNSResolverRemoveDependentByName( const domainname *inName )
1505 {
1506 DNSResolver * p;
1507
1508 check( inName );
1509
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.
1513
1514 do
1515 {
1516 for( p = gDNSResolverList; p; p = p->next )
1517 {
1518 if( ( p->flags & kDNSResolverFlagAutoReleaseByName ) && SameDomainName( &p->info.name, inName ) )
1519 {
1520 DNSResolverRelease( p, 0 );
1521 break;
1522 }
1523 }
1524
1525 } while( p );
1526 }
1527
1528 #if 0
1529 #pragma mark -
1530 #pragma mark == Registration ==
1531 #endif
1532
1533 //===========================================================================================================================
1534 // DNSRegistrationCreate
1535 //===========================================================================================================================
1536
1537 DNSStatus
1538 DNSRegistrationCreate(
1539 DNSRegistrationFlags inFlags,
1540 const char * inName,
1541 const char * inType,
1542 const char * inDomain,
1543 DNSPort inPort,
1544 const void * inTextRecord,
1545 DNSCount inTextRecordSize,
1546 const char * inHost,
1547 const char * inInterfaceName,
1548 DNSRegistrationCallBack inCallBack,
1549 void * inCallBackContext,
1550 DNSRegistrationRef * outRef )
1551 {
1552 DNSStatus err;
1553 size_t size;
1554 DNSRegistration * objectPtr;
1555 mDNSInterfaceID interfaceID;
1556 domainlabel name;
1557 domainname type;
1558 domainname domain;
1559 mDNSIPPort port;
1560 mDNSu8 textRecord[ 256 ];
1561 const mDNSu8 * textRecordPtr;
1562 domainname * host;
1563 domainname tempHost;
1564
1565 objectPtr = mDNSNULL;
1566
1567 // Check parameters.
1568
1569 DNSServicesLock();
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 );
1578
1579 // Default to the local domain when null is passed in.
1580
1581 if( !inDomain )
1582 {
1583 inDomain = kDNSLocalDomain;
1584 }
1585
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.
1588
1589 textRecordPtr = (const mDNSu8 *) inTextRecord;
1590 if( !( inFlags & kDNSRegistrationFlagPreFormattedTextRecord ) )
1591 {
1592 // Convert the raw input text to a length-prefixed text record.
1593
1594 if( inTextRecordSize > 0 )
1595 {
1596 textRecord[ 0 ] = (mDNSu8) inTextRecordSize;
1597 memcpy( &textRecord[ 1 ], inTextRecord, inTextRecordSize );
1598 textRecordPtr = textRecord;
1599 inTextRecordSize += 1;
1600 }
1601 }
1602
1603 // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
1604
1605 size = sizeof( *objectPtr );
1606 if( inTextRecordSize > sizeof( RDataBody ) )
1607 {
1608 size += ( inTextRecordSize - sizeof( RDataBody ) );
1609 }
1610
1611 err = DNSMemAlloc( size, &objectPtr );
1612 require_noerr( err, exit );
1613 memset( objectPtr, 0, size );
1614
1615 objectPtr->flags = inFlags;
1616 objectPtr->callback = inCallBack;
1617 objectPtr->callbackContext = inCallBackContext;
1618
1619 // Set up the interface for interface-specific operations.
1620
1621 if( inInterfaceName && ( *inInterfaceName != '\0' ) )
1622 {
1623 strcpy( objectPtr->interfaceName, inInterfaceName );
1624
1625 err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
1626 require_noerr( err, exit );
1627 }
1628 else
1629 {
1630 interfaceID = mDNSInterface_Any;
1631 }
1632
1633 // Add the object to the list.
1634
1635 objectPtr->next = gDNSRegistrationList;
1636 gDNSRegistrationList = objectPtr;
1637
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.
1641
1642 if( !inName || ( *inName == '\0' ) )
1643 {
1644 name = gMDNSPtr->nicelabel;
1645 inFlags |= kDNSRegistrationFlagAutoRenameOnConflict;
1646 }
1647 else
1648 {
1649 MakeDomainLabelFromLiteralString( &name, inName );
1650 }
1651 MakeDomainNameFromDNSNameString( &type, inType );
1652 MakeDomainNameFromDNSNameString( &domain, inDomain );
1653 port.b[ 0 ] = ( mDNSu8 )( inPort >> 8 );
1654 port.b[ 1 ] = ( mDNSu8 )( inPort >> 0 );
1655
1656 // Set up the host name (if not using the default).
1657
1658 host = mDNSNULL;
1659 if( inHost )
1660 {
1661 host = &tempHost;
1662 MakeDomainNameFromDNSNameString( host, inHost );
1663 AppendDomainName( host, &domain );
1664 }
1665
1666 // Register the service with mDNS.
1667
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 );
1672
1673 if( outRef )
1674 {
1675 *outRef = objectPtr;
1676 }
1677
1678 exit:
1679 if( err && objectPtr )
1680 {
1681 DNSRegistrationRemoveObject( objectPtr );
1682 DNSMemFree( objectPtr );
1683 }
1684 DNSServicesUnlock();
1685 return( err );
1686 }
1687
1688 //===========================================================================================================================
1689 // DNSNoSuchServiceRegistrationCreate
1690 //===========================================================================================================================
1691
1692 DNSStatus
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 )
1702 {
1703 DNSStatus err;
1704 size_t size;
1705 DNSRegistration * objectPtr;
1706 mDNSInterfaceID interfaceID;
1707 domainlabel name;
1708 domainname type;
1709 domainname domain;
1710
1711 objectPtr = mDNSNULL;
1712
1713 // Check parameters.
1714
1715 DNSServicesLock();
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 );
1722
1723 // Default to the local domain when null is passed in.
1724
1725 if( !inDomain )
1726 {
1727 inDomain = kDNSLocalDomain;
1728 }
1729
1730 // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
1731
1732 size = sizeof( *objectPtr );
1733
1734 err = DNSMemAlloc( size, &objectPtr );
1735 require_noerr( err, exit );
1736 memset( objectPtr, 0, size );
1737
1738 objectPtr->flags = inFlags;
1739 objectPtr->callback = inCallBack;
1740 objectPtr->callbackContext = inCallBackContext;
1741
1742 // Set up the interface for interface-specific operations.
1743
1744 if( inInterfaceName && ( *inInterfaceName != '\0' ) )
1745 {
1746 strcpy( objectPtr->interfaceName, inInterfaceName );
1747
1748 err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
1749 require_noerr( err, exit );
1750 }
1751 else
1752 {
1753 interfaceID = mDNSInterface_Any;
1754 }
1755
1756 // Add the object to the list.
1757
1758 objectPtr->next = gDNSRegistrationList;
1759 gDNSRegistrationList = objectPtr;
1760
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.
1763
1764 if( !inName || ( *inName == '\0' ) )
1765 {
1766 name = gMDNSPtr->nicelabel;
1767 }
1768 else
1769 {
1770 MakeDomainLabelFromLiteralString( &name, inName );
1771 }
1772 MakeDomainNameFromDNSNameString( &type, inType );
1773 MakeDomainNameFromDNSNameString( &domain, inDomain );
1774
1775 // Register the service with mDNS.
1776
1777 err = mDNS_RegisterNoSuchService( gMDNSPtr, &objectPtr->set.RR_SRV, &name, &type, &domain, mDNSNULL,
1778 interfaceID, DNSNoSuchServiceRegistrationPrivateCallBack, objectPtr );
1779 require_noerr( err, exit );
1780
1781 if( outRef )
1782 {
1783 *outRef = objectPtr;
1784 }
1785
1786 exit:
1787 if( err && objectPtr )
1788 {
1789 DNSRegistrationRemoveObject( objectPtr );
1790 DNSMemFree( objectPtr );
1791 }
1792 DNSServicesUnlock();
1793 return( err );
1794 }
1795
1796 //===========================================================================================================================
1797 // DNSRegistrationRelease
1798 //===========================================================================================================================
1799
1800 DNSStatus DNSRegistrationRelease( DNSRegistrationRef inRef, DNSRegistrationFlags inFlags )
1801 {
1802 DNSStatus err;
1803 DNSRegistrationEvent event;
1804
1805 DNSServicesLock();
1806 require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
1807 require_action( inRef, exit, err = kDNSBadReferenceErr );
1808 require_action( ( inFlags & ~kDNSRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
1809
1810 // Notify the client of the registration release. Remove the object first so they cannot try to use it in the callback.
1811
1812 inRef = DNSRegistrationRemoveObject( inRef );
1813 require_action( inRef, exit, err = kDNSBadReferenceErr );
1814
1815 if( inRef->callback )
1816 {
1817 memset( &event, 0, sizeof( event ) );
1818 event.type = kDNSRegistrationEventTypeRelease;
1819 inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
1820 }
1821
1822 // Deregister from mDNS after everything else since it will call us back to free the memory.
1823
1824 if( !( inRef->flags & kDNSRegistrationFlagPrivateNoSuchService ) )
1825 {
1826 err = mDNS_DeregisterService( gMDNSPtr, &inRef->set );
1827 require_noerr( err, exit );
1828 }
1829 else
1830 {
1831 err = mDNS_DeregisterNoSuchService( gMDNSPtr, &inRef->set.RR_SRV );
1832 require_noerr( err, exit );
1833 }
1834
1835 // Note: Don't free here. Wait for mDNS to call us back with a mem free result.
1836
1837 exit:
1838 DNSServicesUnlock();
1839 return( err );
1840 }
1841
1842 //===========================================================================================================================
1843 // DNSRegistrationUpdate
1844 //===========================================================================================================================
1845
1846 DNSStatus
1847 DNSRegistrationUpdate(
1848 DNSRegistrationRef inRef,
1849 DNSRecordFlags inFlags,
1850 DNSRegistrationRecordRef inRecord,
1851 const void * inData,
1852 DNSCount inSize,
1853 DNSUInt32 inNewTTL )
1854 {
1855 DNSStatus err;
1856 AuthRecord * rr;
1857 size_t maxRDLength;
1858 RData * newRData;
1859
1860 newRData = mDNSNULL;
1861
1862 DNSServicesLock();
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 );
1867
1868 // If a non-NULL record is specified, update it. Otherwise, use the standard TXT record.
1869
1870 if( inRecord )
1871 {
1872 // $$$ TO DO: Add support for updating extra records (support adding and removing them too).
1873
1874 rr = mDNSNULL;
1875 err = kDNSUnsupportedErr;
1876 require_noerr( err, exit );
1877 }
1878 else
1879 {
1880 rr = &inRef->set.RR_TXT;
1881 }
1882
1883 // Allocate storage for the new data and set it up.
1884
1885 maxRDLength = sizeof( RDataBody );
1886 if( inSize > maxRDLength )
1887 {
1888 maxRDLength = inSize;
1889 }
1890 err = DNSMemAlloc( ( sizeof( *newRData ) - sizeof( RDataBody ) ) + maxRDLength, &newRData );
1891 require_noerr( err, exit );
1892
1893 newRData->MaxRDLength = (mDNSu16) maxRDLength;
1894 memcpy( &newRData->u, inData, inSize );
1895
1896 // Update the record with mDNS.
1897
1898 err = mDNS_Update( gMDNSPtr, rr, inNewTTL, (mDNSu16) inSize, newRData, DNSRegistrationUpdateCallBack );
1899 require_noerr( err, exit );
1900
1901 newRData = mDNSNULL;
1902
1903 exit:
1904 if( newRData )
1905 {
1906 DNSMemFree( newRData );
1907 }
1908 DNSServicesUnlock();
1909 return( err );
1910 }
1911
1912 //===========================================================================================================================
1913 // DNSRegistrationPrivateCallBack
1914 //===========================================================================================================================
1915
1916 mDNSlocal void DNSRegistrationPrivateCallBack( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult )
1917 {
1918 DNSRegistrationRef object;
1919 DNSRegistrationEvent event;
1920
1921 DNS_UNUSED( inMDNS );
1922
1923 DNSServicesLock();
1924
1925 // Exit if object is no longer valid. Should never happen.
1926
1927 object = (DNSRegistrationRef) inSet->ServiceContext;
1928 require( object, exit );
1929
1930 // Dispatch based on the status code.
1931
1932 switch( inResult )
1933 {
1934 case mStatus_NoError:
1935 debugf( DEBUG_NAME "registration callback: \"%##s\" name successfully registered", inSet->RR_SRV.resrec.name.c );
1936
1937 // Notify the client of a successful registration.
1938
1939 if( object->callback )
1940 {
1941 memset( &event, 0, sizeof( event ) );
1942 event.type = kDNSRegistrationEventTypeRegistered;
1943 object->callback( object->callbackContext, object, kDNSNoErr, &event );
1944 }
1945 break;
1946
1947 case mStatus_NameConflict:
1948 {
1949 DNSStatus err;
1950 mDNSBool remove;
1951
1952 debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inSet->RR_SRV.resrec.name.c );
1953
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.
1956
1957 remove = mDNStrue;
1958 if( object->flags & kDNSRegistrationFlagAutoRenameOnConflict )
1959 {
1960 err = mDNS_RenameAndReregisterService( inMDNS, inSet, mDNSNULL );
1961 check_noerr( err );
1962 if( err == mStatus_NoError )
1963 {
1964 debugf( DEBUG_NAME "registration callback: auto-renamed to \"%##s\"", inSet->RR_SRV.resrec.name.c );
1965 remove = mDNSfalse;
1966 }
1967 }
1968 if( remove )
1969 {
1970 object = DNSRegistrationRemoveObject( object );
1971 require( object, exit );
1972
1973 // Notify the client of the name collision.
1974
1975 if( object->callback )
1976 {
1977 memset( &event, 0, sizeof( event ) );
1978 event.type = kDNSRegistrationEventTypeNameCollision;
1979 object->callback( object->callbackContext, object, kDNSNoErr, &event );
1980 }
1981
1982 // Notify the client that the registration is being released.
1983
1984 if( object->callback )
1985 {
1986 memset( &event, 0, sizeof( event ) );
1987 event.type = kDNSRegistrationEventTypeRelease;
1988 object->callback( object->callbackContext, object, kDNSNoErr, &event );
1989 }
1990
1991 // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
1992
1993 DNSMemFree( object );
1994 }
1995 break;
1996 }
1997
1998 case mStatus_MemFree:
1999 debugf( DEBUG_NAME "registration callback: \"%##s\" memory free", inSet->RR_SRV.resrec.name.c );
2000
2001 if( object->set.RR_TXT.resrec.rdata != &object->set.RR_TXT.rdatastorage )
2002 {
2003 // Standard TXT record was updated with new data so free that data separately.
2004
2005 DNSMemFree( object->set.RR_TXT.resrec.rdata );
2006 }
2007 DNSMemFree( object );
2008 break;
2009
2010 default:
2011 debugf( DEBUG_NAME "registration callback: \"%##s\" unknown result %d", inSet->RR_SRV.resrec.name.c, inResult );
2012 break;
2013 }
2014
2015 exit:
2016 DNSServicesUnlock();
2017 }
2018
2019 //===========================================================================================================================
2020 // DNSNoSuchServiceRegistrationPrivateCallBack
2021 //===========================================================================================================================
2022
2023 mDNSlocal void DNSNoSuchServiceRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, mStatus inResult )
2024 {
2025 DNSRegistrationRef object;
2026 DNSRegistrationEvent event;
2027
2028 DNS_UNUSED( inMDNS );
2029
2030 DNSServicesLock();
2031
2032 // Exit if object is no longer valid. Should never happen.
2033
2034 object = (DNSRegistrationRef) inRR->RecordContext;
2035 require( object, exit );
2036
2037 // Dispatch based on the status code.
2038
2039 switch( inResult )
2040 {
2041 case mStatus_NoError:
2042 debugf( DEBUG_NAME "registration callback: \"%##s\" name successfully registered", inRR->resrec.name.c );
2043
2044 // Notify the client of a successful registration.
2045
2046 if( object->callback )
2047 {
2048 memset( &event, 0, sizeof( event ) );
2049 event.type = kDNSRegistrationEventTypeRegistered;
2050 object->callback( object->callbackContext, object, kDNSNoErr, &event );
2051 }
2052 break;
2053
2054 case mStatus_NameConflict:
2055 {
2056 debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inRR->resrec.name.c );
2057
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.
2064
2065 object = DNSRegistrationRemoveObject( object );
2066 require( object, exit );
2067
2068 // Notify the client of the name collision.
2069
2070 if( object->callback )
2071 {
2072 memset( &event, 0, sizeof( event ) );
2073 event.type = kDNSRegistrationEventTypeNameCollision;
2074 object->callback( object->callbackContext, object, kDNSNoErr, &event );
2075 }
2076
2077 // Notify the client that the registration is being released.
2078
2079 if( object->callback )
2080 {
2081 memset( &event, 0, sizeof( event ) );
2082 event.type = kDNSRegistrationEventTypeRelease;
2083 object->callback( object->callbackContext, object, kDNSNoErr, &event );
2084 }
2085
2086 // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
2087
2088 DNSMemFree( object );
2089 break;
2090 }
2091
2092 case mStatus_MemFree:
2093 debugf( DEBUG_NAME "registration callback: \"%##s\" memory free", inRR->resrec.name.c );
2094
2095 DNSMemFree( object );
2096 break;
2097
2098 default:
2099 debugf( DEBUG_NAME "registration callback: \"%##s\" unknown result %d", inRR->resrec.name.c, inResult );
2100 break;
2101 }
2102
2103 exit:
2104 DNSServicesUnlock();
2105 }
2106
2107 //===========================================================================================================================
2108 // DNSRegistrationUpdateCallBack
2109 //===========================================================================================================================
2110
2111 mDNSlocal void DNSRegistrationUpdateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldData )
2112 {
2113 DNS_UNUSED( inMDNS );
2114
2115 check( inRR );
2116 check( inOldData );
2117
2118 if( inOldData != &inRR->rdatastorage )
2119 {
2120 DNSMemFree( inOldData );
2121 }
2122 }
2123
2124 //===========================================================================================================================
2125 // DNSRegistrationFindObject
2126 //
2127 // Warning: Assumes the DNS lock is held.
2128 //===========================================================================================================================
2129
2130 mDNSlocal DNSRegistrationRef * DNSRegistrationFindObject( DNSRegistrationRef inRef )
2131 {
2132 DNSRegistration ** p;
2133
2134 for( p = &gDNSRegistrationList; *p; p = &( *p )->next )
2135 {
2136 if( *p == inRef )
2137 {
2138 break;
2139 }
2140 }
2141 return( p );
2142 }
2143
2144 //===========================================================================================================================
2145 // DNSRegistrationRemoveObject
2146 //
2147 // Warning: Assumes the DNS lock is held.
2148 //===========================================================================================================================
2149
2150 mDNSlocal DNSRegistrationRef DNSRegistrationRemoveObject( DNSRegistrationRef inRef )
2151 {
2152 DNSRegistration ** p;
2153 DNSRegistration * found;
2154
2155 for( p = &gDNSRegistrationList; *p; p = &( *p )->next )
2156 {
2157 if( *p == inRef )
2158 {
2159 break;
2160 }
2161 }
2162 found = *p;
2163 if( found )
2164 {
2165 *p = found->next;
2166 }
2167 return( found );
2168 }
2169
2170 #if 0
2171 #pragma mark -
2172 #pragma mark == Domain Registration ==
2173 #endif
2174
2175 //===========================================================================================================================
2176 // DNSDomainRegistrationCreate
2177 //===========================================================================================================================
2178
2179 DNSStatus
2180 DNSDomainRegistrationCreate(
2181 DNSDomainRegistrationFlags inFlags,
2182 const char * inName,
2183 DNSDomainRegistrationType inType,
2184 DNSDomainRegistrationRef * outRef )
2185 {
2186 DNSStatus err;
2187 DNSDomainRegistration * objectPtr;
2188
2189 objectPtr = mDNSNULL;
2190
2191 // Check parameters.
2192
2193 DNSServicesLock();
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 );
2198
2199 // Allocate the object and set it up.
2200
2201 err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
2202 require_noerr( err, exit );
2203 memset( objectPtr, 0, sizeof( *objectPtr ) );
2204
2205 objectPtr->flags = inFlags;
2206
2207 // Add the object to the list.
2208
2209 objectPtr->next = gDNSDomainRegistrationList;
2210 gDNSDomainRegistrationList = objectPtr;
2211
2212 // Register the domain with mDNS.
2213
2214 err = mDNS_AdvertiseDomains( gMDNSPtr, &objectPtr->rr, (mDNS_DomainType) inType, mDNSInterface_Any, (char *) inName );
2215 require_noerr( err, exit );
2216
2217 if( outRef )
2218 {
2219 *outRef = objectPtr;
2220 }
2221
2222 exit:
2223 if( err && objectPtr )
2224 {
2225 DNSDomainRegistrationRemoveObject( objectPtr );
2226 DNSMemFree( objectPtr );
2227 }
2228 DNSServicesUnlock();
2229 return( err );
2230 }
2231
2232 //===========================================================================================================================
2233 // DNSDomainRegistrationRelease
2234 //===========================================================================================================================
2235
2236 DNSStatus DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef, DNSDomainRegistrationFlags inFlags )
2237 {
2238 DNSStatus err;
2239
2240 DNSServicesLock();
2241 require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
2242 require_action( inRef, exit, err = kDNSBadReferenceErr );
2243 require_action( ( inFlags & ~kDNSDomainRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
2244
2245 // Remove the object and deregister the domain with mDNS.
2246
2247 inRef = DNSDomainRegistrationRemoveObject( inRef );
2248 require_action( inRef, exit, err = kDNSBadReferenceErr );
2249
2250 mDNS_StopAdvertiseDomains( gMDNSPtr, &inRef->rr );
2251
2252 // Release the memory used by the object.
2253
2254 DNSMemFree( inRef );
2255 err = kDNSNoErr;
2256
2257 exit:
2258 DNSServicesUnlock();
2259 return( err );
2260 }
2261
2262 //===========================================================================================================================
2263 // DNSDomainRegistrationRemoveObject
2264 //
2265 // Warning: Assumes the DNS lock is held.
2266 //===========================================================================================================================
2267
2268 mDNSlocal DNSDomainRegistrationRef DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef )
2269 {
2270 DNSDomainRegistration ** p;
2271 DNSDomainRegistration * found;
2272
2273 for( p = &gDNSDomainRegistrationList; *p; p = &( *p )->next )
2274 {
2275 if( *p == inRef )
2276 {
2277 break;
2278 }
2279 }
2280 found = *p;
2281 if( found )
2282 {
2283 *p = found->next;
2284 }
2285 return( found );
2286 }
2287
2288 #if 0
2289 #pragma mark -
2290 #pragma mark == Domain Registration ==
2291 #endif
2292
2293 //===========================================================================================================================
2294 // DNSHostRegistrationCreate
2295 //===========================================================================================================================
2296
2297 DNSStatus
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 )
2307 {
2308 DNSStatus err;
2309 domainname name;
2310 DNSHostRegistration * object;
2311 mDNSInterfaceID interfaceID;
2312 mDNSv4Addr ip;
2313 char buffer[ 64 ];
2314
2315 object = mDNSNULL;
2316
2317 // Check parameters.
2318
2319 DNSServicesLock();
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 );
2326
2327 // Default to the local domain when null is passed in.
2328
2329 if( !inDomain )
2330 {
2331 inDomain = kDNSLocalDomain;
2332 }
2333
2334 // If the caller only wants to add if not found, check if a host with this name was already registered.
2335
2336 MakeDomainNameFromDNSNameString( &name, inName );
2337 AppendDNSNameString( &name, inDomain );
2338
2339 if( inFlags & kDNSHostRegistrationFlagOnlyIfNotFound )
2340 {
2341 object = DNSHostRegistrationFindObjectByName( &name );
2342 if( object )
2343 {
2344 ++object->refCount;
2345 if( outRef )
2346 {
2347 *outRef = object;
2348 }
2349 object = mDNSNULL;
2350 err = kDNSNoErr;
2351 goto exit;
2352 }
2353 }
2354
2355 // Allocate the object and set it up.
2356
2357 err = DNSMemAlloc( sizeof( *object ), &object );
2358 require_noerr( err, exit );
2359 memset( object, 0, sizeof( *object ) );
2360
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;
2367
2368 // Set up the interface for interface-specific operations.
2369
2370 if( inInterfaceName && ( *inInterfaceName != '\0' ) )
2371 {
2372 strcpy( object->interfaceName, inInterfaceName );
2373
2374 err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
2375 require_noerr( err, exit );
2376 }
2377 else
2378 {
2379 interfaceID = mDNSInterface_Any;
2380 }
2381
2382 // Convert the IP address to a format suitable for mDNS.
2383
2384 ip.NotAnInteger = inAddr->u.ipv4.addr.v32;
2385
2386 // Set up the resource records and name.
2387
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 );
2392
2393 AssignDomainName( object->RR_A.resrec.name, name );
2394
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 );
2397
2398 object->RR_A.resrec.rdata->u.ip = ip;
2399 AssignDomainName( object->RR_PTR.resrec.rdata->u.name, object->RR_A.resrec.name );
2400
2401 // Add the object to the list.
2402
2403 object->next = gDNSHostRegistrationList;
2404 gDNSHostRegistrationList = object;
2405
2406 // Register with mDNS.
2407
2408 err = mDNS_Register( gMDNSPtr, &object->RR_A );
2409 require_noerr( err, exit );
2410
2411 err = mDNS_Register( gMDNSPtr, &object->RR_PTR );
2412 if( err != mStatus_NoError )
2413 {
2414 mDNS_Deregister( gMDNSPtr, &object->RR_A );
2415 }
2416 require_noerr( err, exit );
2417
2418 if( outRef )
2419 {
2420 *outRef = object;
2421 }
2422
2423 exit:
2424 if( err && object )
2425 {
2426 DNSHostRegistration ** p;
2427
2428 p = DNSHostRegistrationFindObject( object );
2429 *p = object->next;
2430 DNSMemFree( object );
2431 }
2432 DNSServicesUnlock();
2433 return( err );
2434 }
2435
2436 //===========================================================================================================================
2437 // DNSHostRegistrationRelease
2438 //===========================================================================================================================
2439
2440 DNSStatus DNSHostRegistrationRelease( DNSHostRegistrationRef inRef, DNSHostRegistrationFlags inFlags )
2441 {
2442 DNSStatus err;
2443 DNSHostRegistrationRef * p;
2444
2445 DNSServicesLock();
2446 require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
2447 require_action( inRef, exit, err = kDNSBadReferenceErr );
2448 require_action( ( inFlags & ~kDNSHostRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
2449
2450 // Decrement the reference count and if it drops to 0, remove the object and deregister with mDNS.
2451
2452 p = DNSHostRegistrationFindObject( inRef );
2453 inRef = *p;
2454 require_action( inRef, exit, err = kDNSBadReferenceErr );
2455
2456 check( inRef->refCount > 0 );
2457 if( --inRef->refCount == 0 )
2458 {
2459 *p = inRef->next;
2460
2461 mDNS_Deregister( gMDNSPtr, &inRef->RR_A );
2462 mDNS_Deregister( gMDNSPtr, &inRef->RR_PTR );
2463
2464 // Release the memory used by the object.
2465
2466 DNSMemFree( inRef );
2467 }
2468 err = kDNSNoErr;
2469
2470 exit:
2471 DNSServicesUnlock();
2472 return( err );
2473 }
2474
2475 //===========================================================================================================================
2476 // DNSHostRegistrationFindObject
2477 //
2478 // Warning: Assumes the DNS lock is held.
2479 //===========================================================================================================================
2480
2481 mDNSlocal DNSHostRegistrationRef * DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef )
2482 {
2483 DNSHostRegistration ** p;
2484
2485 for( p = &gDNSHostRegistrationList; *p; p = &( *p )->next )
2486 {
2487 if( *p == inRef )
2488 {
2489 break;
2490 }
2491 }
2492 return( p );
2493 }
2494
2495 //===========================================================================================================================
2496 // DNSHostRegistrationFindObjectByName
2497 //
2498 // Warning: Assumes the DNS lock is held.
2499 //===========================================================================================================================
2500
2501 mDNSlocal DNSHostRegistrationRef DNSHostRegistrationFindObjectByName( const domainname *inName )
2502 {
2503 DNSHostRegistration * p;
2504
2505 check( inName );
2506
2507 for( p = gDNSHostRegistrationList; p; p = p->next )
2508 {
2509 if( SameDomainName( &p->RR_A.resrec.name, inName ) )
2510 {
2511 break;
2512 }
2513 }
2514 return( p );
2515 }
2516
2517 //===========================================================================================================================
2518 // DNSHostRegistrationPrivateCallBack
2519 //===========================================================================================================================
2520
2521 mDNSlocal void DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord *const inRR, mStatus inResult )
2522 {
2523 DNSHostRegistrationRef object;
2524
2525 DNS_UNUSED( inMDNS );
2526
2527 DNSServicesLock();
2528
2529 // Exit if object is no longer valid. Should never happen.
2530
2531 object = (DNSHostRegistrationRef) inRR->RecordContext;
2532 require( object, exit );
2533
2534 // Dispatch based on the status code.
2535
2536 if( inResult == mStatus_NoError )
2537 {
2538 debugf( DEBUG_NAME "host registration callback: \"%##s\" name successfully registered", inRR->resrec.name.c );
2539 if( object->callback )
2540 {
2541 object->callback( object->callbackContext, object, kDNSNoErr, mDNSNULL );
2542 }
2543 }
2544 else if( inResult == mStatus_NameConflict )
2545 {
2546 debugf( DEBUG_NAME "host registration callback: \"%##s\" name conflict", inRR->resrec.name.c );
2547
2548 if( object->flags & kDNSHostRegistrationFlagAutoRenameOnConflict )
2549 {
2550 DNSStatus err;
2551 domainname name;
2552
2553 // De-register any resource records still registered.
2554
2555 if( object->RR_A.resrec.RecordType )
2556 {
2557 mDNS_Deregister( gMDNSPtr, &object->RR_A );
2558 }
2559 if( object->RR_PTR.resrec.RecordType )
2560 {
2561 mDNS_Deregister( gMDNSPtr, &object->RR_PTR );
2562 }
2563
2564 // Rename the host and re-register to try again.
2565
2566 IncrementLabelSuffix( &object->name, mDNSfalse );
2567 name.c[ 0 ] = 0;
2568 AppendDomainLabel( &name, &object->name );
2569 AppendDomainLabel( &name, &object->domain );
2570 AssignDomainName( object->RR_PTR.resrec.name, name );
2571
2572 err = mDNS_Register( gMDNSPtr, &object->RR_A );
2573 check_noerr( err );
2574
2575 err = mDNS_Register( gMDNSPtr, &object->RR_PTR );
2576 check_noerr( err );
2577 }
2578 else
2579 {
2580 if( object->callback )
2581 {
2582 object->callback( object->callbackContext, object, kDNSNameConflictErr, mDNSNULL );
2583 }
2584 }
2585 }
2586 else
2587 {
2588 debugf( DEBUG_NAME "host registration callback: \"%##s\" unknown result", inRR->resrec.name.c, inResult );
2589 }
2590
2591 exit:
2592 DNSServicesUnlock();
2593 }
2594
2595 #if 0
2596 #pragma mark -
2597 #pragma mark == Utilities ==
2598 #endif
2599
2600 //===========================================================================================================================
2601 // DNSMemAlloc
2602 //===========================================================================================================================
2603
2604 mDNSlocal DNSStatus DNSMemAlloc( size_t inSize, void *outMem )
2605 {
2606 void * mem;
2607
2608 check( inSize > 0 );
2609 check( outMem );
2610
2611 mem = malloc( inSize );
2612 *( (void **) outMem ) = mem;
2613 if( mem )
2614 {
2615 return( kDNSNoErr );
2616 }
2617 return( kDNSNoMemoryErr );
2618 }
2619
2620 //===========================================================================================================================
2621 // DNSMemFree
2622 //===========================================================================================================================
2623
2624 mDNSlocal void DNSMemFree( void *inMem )
2625 {
2626 check( inMem );
2627
2628 free( inMem );
2629 }
2630
2631 //===========================================================================================================================
2632 // DNSDynamicTextRecordBuildEscaped
2633 //===========================================================================================================================
2634
2635 DNSStatus DNSDynamicTextRecordBuildEscaped( const char *inFormat, void *outTextRecord, size_t *outSize )
2636 {
2637 DNSStatus err;
2638 size_t size;
2639 void * textRecord;
2640
2641 textRecord = NULL;
2642
2643 // Calculate the size of the built text record, allocate a buffer for it, then build it in that buffer.
2644
2645 err = DNSTextRecordValidate( inFormat, 0x7FFFFFFF, NULL, &size );
2646 require_noerr( err, exit );
2647
2648 textRecord = malloc( size );
2649 require_action( textRecord, exit, err = kDNSNoMemoryErr );
2650
2651 err = DNSTextRecordValidate( inFormat, size, textRecord, &size );
2652 require_noerr( err, exit );
2653
2654 // Success!
2655
2656 if( outTextRecord )
2657 {
2658 *( (void **) outTextRecord ) = textRecord;
2659 textRecord = NULL;
2660 }
2661 if( outSize )
2662 {
2663 *outSize = size;
2664 }
2665
2666 exit:
2667 if( textRecord )
2668 {
2669 free( textRecord );
2670 }
2671 return( err );
2672 }
2673
2674 //===========================================================================================================================
2675 // DNSDynamicTextRecordAppendCString
2676 //===========================================================================================================================
2677
2678 DNSStatus DNSDynamicTextRecordAppendCString( void *ioTxt, size_t *ioTxtSize, const char *inName, const char *inValue )
2679 {
2680 DNSStatus err;
2681 size_t valueSize;
2682
2683 require_action( inName, exit, err = kDNSBadParamErr );
2684 require_action( inValue, exit, err = kDNSBadParamErr );
2685
2686 if( inValue != kDNSTextRecordStringNoValue )
2687 {
2688 valueSize = strlen( inValue );
2689 }
2690 else
2691 {
2692 valueSize = kDNSTextRecordNoSize;
2693 }
2694 err = DNSDynamicTextRecordAppendData( ioTxt, ioTxtSize, inName, inValue, valueSize );
2695 require_noerr( err, exit );
2696
2697 exit:
2698 return( err );
2699 }
2700
2701 //===========================================================================================================================
2702 // DNSDynamicTextRecordAppendData
2703 //===========================================================================================================================
2704
2705 DNSStatus
2706 DNSDynamicTextRecordAppendData(
2707 void * ioTxt,
2708 size_t * ioTxtSize,
2709 const char * inName,
2710 const void * inValue,
2711 size_t inValueSize )
2712 {
2713 DNSStatus err;
2714 size_t oldSize;
2715 size_t newSize;
2716 int hasName;
2717 int hasValue;
2718 void ** bufferPtr;
2719 void * newBuffer;
2720
2721 require_action( ioTxt, exit, err = kDNSBadParamErr );
2722 require_action( ioTxtSize, exit, err = kDNSBadParamErr );
2723 require_action( inName, exit, err = kDNSBadParamErr );
2724
2725 // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
2726
2727 hasName = ( inName != kDNSTextRecordStringNoValue ) && ( *inName != '\0' );
2728 hasValue = ( inValue != kDNSTextRecordNoValue ) && ( inValueSize != kDNSTextRecordNoSize );
2729 require_action( hasName || hasValue, exit, err = kDNSUnsupportedErr );
2730
2731 // Calculate the size needed for the new data (old size + length byte + name size + '=' + value size).
2732
2733 oldSize = *ioTxtSize;
2734 newSize = oldSize + 1; // add length byte size
2735 if( hasName )
2736 {
2737 newSize += strlen( inName ); // add name size
2738 if( hasValue )
2739 {
2740 newSize += 1; // add '=' size
2741 }
2742 }
2743 if( hasValue )
2744 {
2745 newSize += inValueSize; // add value size
2746 }
2747
2748 // Reallocate the buffer to make room for the new data.
2749
2750 bufferPtr = (void **) ioTxt;
2751 newBuffer = realloc( *bufferPtr, newSize );
2752 require_action( newBuffer, exit, err = kDNSNoMemoryErr );
2753 *bufferPtr = newBuffer;
2754
2755 err = DNSTextRecordAppendData( newBuffer, oldSize, newSize, inName, inValue, inValueSize, &newSize );
2756 require_noerr( err, exit );
2757
2758 // Success!
2759
2760 *ioTxtSize = newSize;
2761
2762 exit:
2763 return( err );
2764 }
2765
2766 //===========================================================================================================================
2767 // DNSDynamicTextRecordRelease
2768 //===========================================================================================================================
2769
2770 void DNSDynamicTextRecordRelease( void *inTxt )
2771 {
2772 if( inTxt )
2773 {
2774 free( inTxt );
2775 }
2776 }
2777
2778 //===========================================================================================================================
2779 // DNSTextRecordAppendCString
2780 //===========================================================================================================================
2781
2782 DNSStatus
2783 DNSTextRecordAppendCString(
2784 void * inTxt,
2785 size_t inTxtSize,
2786 size_t inTxtMaxSize,
2787 const char * inName,
2788 const char * inValue,
2789 size_t * outTxtSize )
2790 {
2791 DNSStatus err;
2792 size_t valueSize;
2793
2794 require_action( inName, exit, err = kDNSBadParamErr );
2795 require_action( inValue, exit, err = kDNSBadParamErr );
2796
2797 if( inValue != kDNSTextRecordStringNoValue )
2798 {
2799 valueSize = strlen( inValue );
2800 }
2801 else
2802 {
2803 valueSize = kDNSTextRecordNoSize;
2804 }
2805 err = DNSTextRecordAppendData( inTxt, inTxtSize, inTxtMaxSize, inName, inValue, valueSize, outTxtSize );
2806 require_noerr( err, exit );
2807
2808 exit:
2809 return( err );
2810 }
2811
2812 //===========================================================================================================================
2813 // DNSTextRecordAppendData
2814 //===========================================================================================================================
2815
2816 DNSStatus
2817 DNSTextRecordAppendData(
2818 void * inTxt,
2819 size_t inTxtSize,
2820 size_t inTxtMaxSize,
2821 const char * inName,
2822 const void * inValue,
2823 size_t inValueSize,
2824 size_t * outTxtSize )
2825 {
2826 DNSStatus err;
2827 mDNSu8 * p;
2828 int hasName;
2829 int hasValue;
2830 size_t size;
2831 size_t newSize;
2832 const mDNSu8 * q;
2833
2834 require_action( inTxt, exit, err = kDNSBadParamErr );
2835 require_action( inName, exit, err = kDNSBadParamErr );
2836
2837 // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
2838
2839 hasName = ( inName != kDNSTextRecordStringNoValue ) && ( *inName != '\0' );
2840 hasValue = ( inValue != kDNSTextRecordNoValue ) && ( inValueSize != kDNSTextRecordNoSize );
2841 require_action( hasName || hasValue, exit, err = kDNSUnsupportedErr );
2842
2843 // Calculate the size and make sure there is enough total room and enough room in an individual segment.
2844
2845 size = 0;
2846 if( hasName )
2847 {
2848 size += strlen( inName ); // add name size
2849 if( hasValue )
2850 {
2851 size += 1; // add '=' size
2852 }
2853 }
2854 if( hasValue )
2855 {
2856 size += inValueSize; // add value size
2857 }
2858 newSize = inTxtSize + 1 + size; // old size + length byte + new data
2859
2860 require_action( size < 256, exit, err = kDNSNoMemoryErr );
2861 require_action( newSize <= inTxtMaxSize, exit, err = kDNSNoMemoryErr );
2862
2863 // Write the length-prefix byte containing the size of this segment.
2864
2865 p = ( (mDNSu8 *) inTxt ) + inTxtSize;
2866 *p++ = (mDNSu8) size;
2867
2868 // Copy the name.
2869
2870 if( hasName )
2871 {
2872 q = (const mDNSu8 *) inName;
2873 while( *q != '\0' )
2874 {
2875 *p++ = *q++;
2876 }
2877 if( hasValue )
2878 {
2879 *p++ = '=';
2880 }
2881 }
2882 if( hasValue )
2883 {
2884 // Copy the value.
2885
2886 q = (const mDNSu8 *) inValue;
2887 while( inValueSize-- > 0 )
2888 {
2889 *p++ = *q++;
2890 }
2891 }
2892
2893 // Success!
2894
2895 if( outTxtSize )
2896 {
2897 *outTxtSize = newSize;
2898 }
2899 err = kDNSNoErr;
2900
2901 exit:
2902 return( err );
2903 }
2904
2905 //===========================================================================================================================
2906 // DNSTextRecordEscape
2907 //===========================================================================================================================
2908
2909 DNSStatus DNSTextRecordEscape( const void *inTextRecord, size_t inTextSize, char **outEscapedString )
2910 {
2911 DNSStatus err;
2912 const DNSUInt8 * src;
2913 const DNSUInt8 * end;
2914 DNSUInt8 * dstStorage;
2915 DNSUInt8 * dst;
2916 int size;
2917
2918 check( inTextRecord || ( inTextSize == 0 ) );
2919
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.
2923
2924 dstStorage = (DNSUInt8 *) malloc( inTextSize + 1 );
2925 require_action( dstStorage, exit, err = kDNSNoMemoryErr );
2926 dst = dstStorage;
2927
2928 if( inTextSize > 0 )
2929 {
2930 src = (const DNSUInt8 *) inTextRecord;
2931 end = src + inTextSize;
2932 while( src < end )
2933 {
2934 size = *src++;
2935 if( ( src + size ) > end )
2936 {
2937 // Malformed TXT record. Most likely an old-style TXT record.
2938
2939 src = NULL;
2940 break;
2941 }
2942 while( size-- > 0 )
2943 {
2944 *dst++ = *src++;
2945 }
2946 *dst++ = '\001'; // \001 record separator. May be overwritten later if this is the last record.
2947 }
2948 check( ( dst - dstStorage ) <= inTextSize );
2949 if( src != end )
2950 {
2951 // Malformed TXT record. Assume an old-style TXT record and use the TXT record as a whole.
2952
2953 memcpy( dstStorage, inTextRecord, inTextSize );
2954 dstStorage[ inTextSize ] = '\0';
2955 }
2956 else
2957 {
2958 dstStorage[ inTextSize - 1 ] = '\0';
2959 }
2960 }
2961 else
2962 {
2963 // No text record data so just return an empty string.
2964
2965 *dst = '\0';
2966 }
2967
2968 // Success!
2969
2970 if( outEscapedString )
2971 {
2972 *outEscapedString = (char *) dstStorage;
2973 dstStorage = NULL;
2974 }
2975 err = kDNSNoErr;
2976
2977 exit:
2978 if( dstStorage )
2979 {
2980 free( dstStorage );
2981 }
2982 return( err );
2983 }
2984
2985 //===========================================================================================================================
2986 // DNSNameValidate
2987 //===========================================================================================================================
2988
2989 DNSStatus DNSNameValidate( const char *inName )
2990 {
2991 DNSStatus err;
2992 mDNSu8 * p;
2993 domainname name;
2994
2995 p = MakeDomainNameFromDNSNameString( &name, inName );
2996 if( p )
2997 {
2998 err = kDNSNoErr;
2999 }
3000 else
3001 {
3002 err = kDNSBadParamErr;
3003 }
3004 return( err );
3005 }
3006
3007 //===========================================================================================================================
3008 // DNSServiceTypeValidate
3009 //===========================================================================================================================
3010
3011 DNSStatus DNSServiceTypeValidate( const char *inServiceType )
3012 {
3013 DNSStatus err;
3014 mDNSu8 * p;
3015 domainname type;
3016 domainname domain;
3017 domainname fqdn;
3018
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.
3021
3022 p = MakeDomainNameFromDNSNameString( &type, inServiceType );
3023 if( !p )
3024 {
3025 err = kDNSBadParamErr;
3026 goto exit;
3027 }
3028
3029 p = MakeDomainNameFromDNSNameString( &domain, "local." );
3030 if( !p )
3031 {
3032 err = kDNSBadParamErr;
3033 goto exit;
3034 }
3035
3036 p = ConstructServiceName( &fqdn, mDNSNULL, &type, &domain );
3037 if( !p )
3038 {
3039 err = kDNSBadParamErr;
3040 goto exit;
3041 }
3042
3043 err = kDNSNoErr;
3044
3045 exit:
3046 return( err );
3047 }
3048
3049 //===========================================================================================================================
3050 // DNSTextRecordValidate
3051 //===========================================================================================================================
3052
3053 DNSStatus DNSTextRecordValidate( const char *inText, size_t inMaxSize, void *outRecord, size_t *outActualSize )
3054 {
3055 DNSStatus err;
3056 const mDNSu8 * p;
3057 size_t totalSize;
3058 mDNSu8 sectionSize;
3059 mDNSu8 * dst;
3060 mDNSu8 * section;
3061
3062 require_action( inText, exit, err = kDNSBadParamErr );
3063
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.
3067
3068 totalSize = 0;
3069 sectionSize = 0;
3070 dst = (mDNSu8 *) outRecord;
3071 section = dst;
3072
3073 p = (const mDNSu8 *) inText;
3074 while( *p != '\0' )
3075 {
3076 ++totalSize;
3077 if( totalSize >= inMaxSize )
3078 {
3079 err = kDNSBadParamErr;
3080 goto exit;
3081 }
3082
3083 if( *p == '\001' )
3084 {
3085 // Separator Escape sequence, start a new string section.
3086
3087 if( sectionSize <= 0 )
3088 {
3089 err = kDNSBadParamErr;
3090 goto exit;
3091 }
3092 sectionSize = 0;
3093 if( section )
3094 {
3095 section = &dst[ totalSize ];
3096 section[ 0 ] = 0;
3097 }
3098 }
3099 else
3100 {
3101 if( sectionSize >= 255 )
3102 {
3103 err = kDNSBadParamErr;
3104 goto exit;
3105 }
3106 ++sectionSize;
3107 if( section )
3108 {
3109 section[ 0 ] = sectionSize;
3110 section[ sectionSize ] = *p;
3111 }
3112 }
3113 ++p;
3114 }
3115 ++totalSize;
3116
3117 // Success!
3118
3119 if( outActualSize )
3120 {
3121 *outActualSize = totalSize;
3122 }
3123 err = kDNSNoErr;
3124
3125 exit:
3126 return( err );
3127 }
3128
3129 //===========================================================================================================================
3130 // MDNSAddrToDNSAddress
3131 //===========================================================================================================================
3132
3133 mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, DNSNetworkAddress *outAddr )
3134 {
3135 switch( inAddr->type )
3136 {
3137 case mDNSAddrType_IPv4:
3138 outAddr->addressType = kDNSNetworkAddressTypeIPv4;
3139 outAddr->u.ipv4.addr.v32 = inAddr->ip.v4.NotAnInteger;
3140 break;
3141
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 ];
3148 break;
3149
3150 default:
3151 outAddr->addressType = kDNSNetworkAddressTypeInvalid;
3152 break;
3153 }
3154 }
3155
3156 #ifdef __cplusplus
3157 }
3158 #endif