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