]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/DNSSDDirect.c
c20a97e2afdf9533e344dd5a293ab3d72b161e21
[apple/mdnsresponder.git] / mDNSWindows / DNSSDDirect.c
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: DNSSDDirect.c,v $
28 Revision 1.7 2004/06/05 00:04:27 cheshire
29 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
30
31 Revision 1.6 2004/05/08 12:25:50 bradley
32 Changed to use symbolic enums to prevent some compilers from treating it as a sign conversion.
33
34 Revision 1.5 2004/05/06 18:42:58 ksekar
35 General dns_sd.h API cleanup, including the following radars:
36 <rdar://problem/3592068>: Remove flags with zero value
37 <rdar://problem/3479569>: Passing in NULL causes a crash.
38
39 Revision 1.4 2004/04/15 06:55:50 bradley
40 Changed resolving to manually query for SRV and TXT records instead of using mDNS_StartResolveService.
41 This avoids extra A/AAAA record queries and allows local-only resolves to work with normal services.
42
43 Revision 1.3 2004/04/15 01:00:05 bradley
44 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
45 without .local name resolving support will need to manually query for A/AAAA records as needed.
46
47 Revision 1.2 2004/04/09 21:03:14 bradley
48 Changed port numbers to use network byte order for consistency with other platforms.
49
50 Revision 1.1 2004/01/30 02:46:15 bradley
51 Portable implementation of the DNS-SD API. This interacts with mDNSCore to perform all the real work
52 of the DNS-SD API. This code does not rely on any platform-specifics so it should run on any platform
53 with an mDNS platform plugin available. Software that cannot or does not want to use the IPC mechanism
54 (e.g. Windows CE, VxWorks, etc.) can use this code directly without any of the IPC pieces.
55
56 */
57
58 #include <stdlib.h>
59
60 #include "CommonServices.h"
61 #include "DebugServices.h"
62
63 #include "DNSSD.h"
64
65 #if( DNS_SD_DIRECT_ENABLED )
66
67 #include "mDNSClientAPI.h"
68
69 #include "DNSSDDirect.h"
70
71 #ifdef __cplusplus
72 extern "C" {
73 #endif
74
75 #if 0
76 #pragma mark == Constants ==
77 #endif
78
79 //===========================================================================================================================
80 // Constants
81 //===========================================================================================================================
82
83 #define DEBUG_NAME "[DNS-SD Direct] "
84
85 typedef uint32_t DNSServiceRegisterFlags;
86
87 #define kDNSServiceRegisterFlagsAutoName ( 1 << 0 )
88 #define kDNSServiceRegisterFlagsAutoNameOnFree ( 1 << 1 )
89 #define kDNSServiceRegisterFlagsRenameOnConflict ( 1 << 2 )
90
91 #if 0
92 #pragma mark == Structures ==
93 #endif
94
95 //===========================================================================================================================
96 // Structures
97 //===========================================================================================================================
98
99 typedef void ( *DNSServiceRefReleaseCallBack )( DNSServiceRef inRef );
100
101 // DNSServiceRef
102
103 typedef struct _DNSServiceRef_t _DNSServiceRef_t;
104 struct _DNSServiceRef_t
105 {
106 DNSServiceRef next;
107 DNSServiceRefReleaseCallBack releaseCallBack;
108 void * context;
109
110 union
111 {
112 struct // EnumerateDomains
113 {
114 DNSQuestion question;
115 mDNSBool questionActive;
116 DNSQuestion defaultQuestion;
117 mDNSBool defaultQuestionActive;
118 DNSServiceDomainEnumReply callback;
119
120 } domain;
121
122 struct // Register
123 {
124 ServiceRecordSet * set;
125 domainlabel name;
126 DNSServiceRegisterFlags flags;
127 DNSServiceRegisterReply callback;
128
129 } reg;
130
131 struct // Browse
132 {
133 DNSQuestion question;
134 mDNSBool questionActive;
135 DNSServiceBrowseReply callback;
136
137 } browse;
138
139 struct // Resolve
140 {
141 DNSServiceFlags flags;
142 DNSQuestion srvQuestion;
143 mDNSBool srvQuestionActive;
144 const ResourceRecord * srvAnswer;
145 DNSQuestion txtQuestion;
146 mDNSBool txtQuestionActive;
147 const ResourceRecord * txtAnswer;
148 DNSServiceResolveReply callback;
149
150 } resolve;
151
152 struct // CreateConnection
153 {
154 DNSRecordRef records;
155
156 } connection;
157
158 struct // Query
159 {
160 DNSQuestion question;
161 mDNSBool questionActive;
162 DNSServiceQueryRecordReply callback;
163
164 } query;
165
166 } u;
167 };
168
169 // DNSRecordRef
170
171 typedef struct _DNSRecordRef_t _DNSRecordRef_t;
172 struct _DNSRecordRef_t
173 {
174 union
175 {
176 struct // Service-based records (i.e. DNSServiceRegister-based DNSServiceRef's)
177 {
178 ExtraResourceRecord extra;
179
180 } service;
181
182 struct // Connection-based records (i.e. DNSServiceCreateConnection-based DNSServiceRef's)
183 {
184 DNSRecordRef next;
185 DNSServiceRef owner;
186 DNSServiceRegisterRecordReply callback;
187 void * context;
188 AuthRecord rr;
189
190 } connection;
191
192 } u;
193
194 // WARNING: Do not add fields after the resource record. That is where oversized RData space is allocated.
195 };
196
197 #define kDNSRecordServiceFixedSize sizeof_field( _DNSRecordRef_t, u.service )
198 #define kDNSRecordConnectionFixedSize sizeof_field( _DNSRecordRef_t, u.connection )
199
200 #if 0
201 #pragma mark == Prototypes ==
202 #endif
203
204 //===========================================================================================================================
205 // Prototypes
206 //===========================================================================================================================
207
208 // General
209
210 #define DNSServiceLock() mDNSPlatformLock( gMDNSPtr )
211 #define DNSServiceUnlock() mDNSPlatformUnlock( gMDNSPtr )
212
213 DEBUG_LOCAL void DNSServiceMDNSCallBack( mDNS * const inMDNS, mStatus inStatus );
214
215 // Domain Enumeration
216
217 DEBUG_LOCAL void DNSServiceEnumerateDomainsRelease_direct( DNSServiceRef inRef );
218 DEBUG_LOCAL void
219 DNSServiceEnumerateDomainsCallBack_direct(
220 mDNS * const inMDNS,
221 DNSQuestion * inQuestion,
222 const ResourceRecord * const inAnswer,
223 mDNSBool inAddRecord );
224
225 // Service Discovery
226
227 DEBUG_LOCAL void DNSServiceBrowseRelease_direct( DNSServiceRef inRef );
228 DEBUG_LOCAL void
229 DNSServiceBrowseCallBack_direct(
230 mDNS * const inMDNS,
231 DNSQuestion * inQuestion,
232 const ResourceRecord * const inAnswer,
233 mDNSBool inAddRecord );
234
235 DEBUG_LOCAL void DNSServiceResolveRelease_direct( DNSServiceRef inRef );
236 DEBUG_LOCAL void
237 DNSServiceResolveCallBack_direct(
238 mDNS * const inMDNS,
239 DNSQuestion * inQuestion,
240 const ResourceRecord * const inAnswer,
241 mDNSBool inAddRecord );
242
243 // Service Registration
244
245 DEBUG_LOCAL void DNSServiceRegisterRelease_direct( DNSServiceRef inRef );
246 DEBUG_LOCAL void DNSServiceRegisterCallBack_direct( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult );
247 DEBUG_LOCAL void DNSServiceRegisterFree_direct( DNSServiceRef inRef );
248
249 DEBUG_LOCAL void DNSServiceUpdateRecordCallBack_direct( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldRData );
250
251 // Special Purpose
252
253 DEBUG_LOCAL void DNSServiceCreateConnectionRelease_direct( DNSServiceRef inRef );
254 DEBUG_LOCAL DNSRecordRef DNSServiceConnectionRecordRemove_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef );
255
256 DEBUG_LOCAL void DNSServiceRegisterRecordCallBack_direct( mDNS *const inMDNS, AuthRecord *const inRR, mStatus inResult );
257
258 DEBUG_LOCAL void DNSServiceQueryRecordRelease_direct( DNSServiceRef inRef );
259 DEBUG_STATIC void
260 DNSServiceQueryRecordCallBack_direct(
261 mDNS * const inMDNS,
262 DNSQuestion * inQuestion,
263 const ResourceRecord * const inAnswer,
264 mDNSBool inAddRecord );
265
266 #if 0
267 #pragma mark == Globals ==
268 #endif
269
270 //===========================================================================================================================
271 // Globals
272 //===========================================================================================================================
273
274 mDNS gMDNS;
275 DEBUG_LOCAL mDNS * gMDNSPtr = NULL;
276 DEBUG_LOCAL CacheRecord * gMDNSCache = NULL;
277 DEBUG_LOCAL DNSServiceRef gDNSServiceRefList = NULL;
278 DEBUG_LOCAL DNSServiceRef gDNSCurrentServiceRef = NULL;
279 DEBUG_LOCAL DNSRecordRef gDNSCurrentRecord = NULL;
280
281 #if 0
282 #pragma mark -
283 #pragma mark == General ==
284 #endif
285
286 //===========================================================================================================================
287 // DNSServiceInitialize_direct
288 //===========================================================================================================================
289
290 DNSServiceErrorType DNSServiceInitialize_direct( DNSServiceInitializeFlags inFlags, int inCacheEntryCount )
291 {
292 DNSServiceErrorType err;
293 mDNSBool advertise;
294
295 dlog( kDebugLevelTrace, DEBUG_NAME "initializing (flags=0x%08X, cache=%d/%d)\n", (int) inFlags,
296 inCacheEntryCount, ( inCacheEntryCount == 0 ) ? kDNSServiceCacheEntryCountDefault : inCacheEntryCount );
297
298 // Allocate the record cache.
299
300 if( inCacheEntryCount == 0 )
301 {
302 inCacheEntryCount = kDNSServiceCacheEntryCountDefault;
303 }
304 gMDNSCache = (CacheRecord *) malloc( inCacheEntryCount * sizeof( *gMDNSCache ) );
305 require_action( gMDNSCache, exit, err = kDNSServiceErr_NoMemory );
306
307 // Initialize mDNS.
308
309 if( inFlags & kDNSServiceInitializeFlagsAdvertise )
310 {
311 advertise = mDNS_Init_AdvertiseLocalAddresses;
312 }
313 else
314 {
315 advertise = mDNS_Init_DontAdvertiseLocalAddresses;
316 }
317 err = mDNS_Init( &gMDNS, NULL, gMDNSCache, (mDNSu32) inCacheEntryCount, advertise, DNSServiceMDNSCallBack, NULL );
318 require_noerr( err, exit );
319 err = gMDNS.mDNSPlatformStatus;
320 require_noerr( err, exit );
321
322 gMDNSPtr = &gMDNS;
323
324 exit:
325 dlog( kDebugLevelTrace, DEBUG_NAME "initializing done (err=%d %m)\n", err, err );
326 if( err )
327 {
328 DNSServiceFinalize_direct();
329 }
330 return( err );
331 }
332
333 //===========================================================================================================================
334 // DNSServiceFinalize_direct
335 //===========================================================================================================================
336
337 void DNSServiceFinalize_direct( void )
338 {
339 dlog( kDebugLevelTrace, DEBUG_NAME "finalizing\n" );
340
341 if( gMDNSPtr )
342 {
343 mDNS_Close( &gMDNS );
344 gMDNSPtr = NULL;
345 }
346 if( gMDNSCache )
347 {
348 free( gMDNSCache );
349 gMDNSCache = mDNSNULL;
350 }
351
352 dlog( kDebugLevelTrace, DEBUG_NAME "finalizing done\n" );
353 }
354
355 //===========================================================================================================================
356 // DNSServiceMDNSCallBack
357 //===========================================================================================================================
358
359 DEBUG_LOCAL void DNSServiceMDNSCallBack( mDNS * const inMDNS, mStatus inStatus )
360 {
361 DEBUG_USE_ONLY( inMDNS );
362 check( inMDNS );
363
364 dlog( kDebugLevelTrace, DEBUG_NAME "MDNS callback (status=%d)\n", inStatus );
365
366 if( inStatus == mStatus_ConfigChanged )
367 {
368 // Notify all callbacks that the configuration has changed so they can do any additional processing.
369 //
370 // Warning: This is likely to call a user callback, which may change the object lists. Any code walking
371 // Warning: or changing these lists must use the "current" ptr mechanism to protect against this.
372
373 DNSServiceLock();
374 dlog( kDebugLevelTrace, DEBUG_NAME "handling ConfigChanged\n" );
375
376 check_string( !gDNSCurrentServiceRef, "somebody is already using gDNSCurrentServiceRef!" );
377 gDNSCurrentServiceRef = gDNSServiceRefList;
378 while( gDNSCurrentServiceRef )
379 {
380 DNSServiceRef obj;
381
382 obj = gDNSCurrentServiceRef;
383 gDNSCurrentServiceRef = obj->next;
384
385 // Call the callback with the ConfigChanged error code. Use the releaseCallBack to determine the type.
386
387 if( obj->releaseCallBack == DNSServiceEnumerateDomainsRelease_direct )
388 {
389 obj->u.domain.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", obj->context );
390 }
391 else if( obj->releaseCallBack == DNSServiceRegisterRelease_direct )
392 {
393 // If auto-renaming and the system name has changed then trigger a re-register with the new name.
394
395 if( obj->u.reg.flags & kDNSServiceRegisterFlagsAutoName )
396 {
397 if( !SameDomainLabel( obj->u.reg.name.c, gMDNSPtr->nicelabel.c ) )
398 {
399 mStatus err;
400
401 obj->u.reg.flags |= kDNSServiceRegisterFlagsAutoNameOnFree;
402 err = mDNS_DeregisterService( gMDNSPtr, obj->u.reg.set );
403 check_noerr( err );
404 }
405 }
406 else
407 {
408 check_string( obj->u.reg.callback, "not auto-naming, but no callback?" );
409
410 obj->u.reg.callback( obj, 0, kDNSServiceErr_ConfigChanged, "", "", "", obj->context );
411 }
412 }
413 else if( obj->releaseCallBack == DNSServiceBrowseRelease_direct )
414 {
415 obj->u.browse.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", "", "", obj->context );
416 }
417 else if( obj->releaseCallBack == DNSServiceResolveRelease_direct )
418 {
419 obj->u.resolve.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", "", 0, 0, NULL, obj->context );
420 }
421 else if( obj->releaseCallBack == DNSServiceCreateConnectionRelease_direct )
422 {
423 check_string( !gDNSCurrentRecord, "somebody is already using gDNSCurrentRecord!" );
424 gDNSCurrentRecord = obj->u.connection.records;
425 while( gDNSCurrentRecord )
426 {
427 DNSRecordRef record;
428
429 record = gDNSCurrentRecord;
430 gDNSCurrentRecord = record->u.connection.next;
431
432 record->u.connection.callback( record->u.connection.owner, record, 0, kDNSServiceErr_ConfigChanged,
433 record->u.connection.context );
434 }
435 }
436 else if( obj->releaseCallBack == DNSServiceQueryRecordRelease_direct )
437 {
438 obj->u.query.callback( obj, 0, 0, kDNSServiceErr_ConfigChanged, "", 0, 0, 0,NULL, 0, obj->context );
439 }
440 }
441 DNSServiceUnlock();
442 }
443 }
444
445 #if 0
446 #pragma mark -
447 #endif
448
449 //===========================================================================================================================
450 // DNSServiceRefDeallocate_direct
451 //===========================================================================================================================
452
453 void DNSServiceRefDeallocate_direct( DNSServiceRef inRef )
454 {
455 check( inRef );
456
457 dlog( kDebugLevelNotice, DEBUG_NAME "%s: %#p\n", __ROUTINE__, inRef );
458
459 DNSServiceLock();
460 if( inRef )
461 {
462 DNSServiceRef * p;
463
464 // Remove the object from the list.
465
466 for( p = &gDNSServiceRefList; *p; p = &( *p )->next )
467 {
468 if( *p == inRef )
469 {
470 break;
471 }
472 }
473 check( *p );
474
475 // Release the object if it was found.
476
477 if( *p )
478 {
479 *p = inRef->next;
480
481 // If somebody will be looking at this object next, move the current ptr to the next object.
482
483 if( inRef == gDNSCurrentServiceRef )
484 {
485 dlog( kDebugLevelInfo, DEBUG_NAME "deleting gDNSCurrentServiceRef (%#p)\n", inRef );
486 gDNSCurrentServiceRef = inRef->next;
487 }
488
489 check( inRef->releaseCallBack );
490 if( inRef->releaseCallBack )
491 {
492 inRef->releaseCallBack( inRef );
493 }
494 }
495 }
496 DNSServiceUnlock();
497 }
498
499 #if 0
500 #pragma mark -
501 #pragma mark == Domain Enumeration ==
502 #endif
503
504 //===========================================================================================================================
505 // DNSServiceEnumerateDomains_direct
506 //===========================================================================================================================
507
508 DNSServiceErrorType
509 DNSServiceEnumerateDomains_direct(
510 DNSServiceRef * outRef,
511 const DNSServiceFlags inFlags,
512 const uint32_t inInterfaceIndex,
513 const DNSServiceDomainEnumReply inCallBack,
514 void * inContext )
515 {
516 DNSServiceErrorType err;
517 DNSServiceRef obj;
518 mDNS_DomainType type;
519 mDNS_DomainType defaultType;
520 DNSServiceFlags flags;
521 mDNSInterfaceID interfaceID;
522
523 obj = NULL;
524 DNSServiceLock();
525 require_action( outRef, exit, err = kDNSServiceErr_BadParam );
526 require_action( ( inFlags == kDNSServiceFlagsBrowseDomains ) ||
527 ( inFlags == kDNSServiceFlagsRegistrationDomains ),
528 exit, err = kDNSServiceErr_BadFlags );
529 require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
530
531 // Allocate and initialize the object.
532
533 obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
534 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
535
536 obj->releaseCallBack = DNSServiceEnumerateDomainsRelease_direct;
537 obj->context = inContext;
538 obj->u.domain.callback = inCallBack;
539
540 obj->next = gDNSServiceRefList;
541 gDNSServiceRefList = obj;
542
543 // Start the browse operations.
544
545 if( inFlags & kDNSServiceFlagsRegistrationDomains )
546 {
547 type = mDNS_DomainTypeRegistration;
548 defaultType = mDNS_DomainTypeRegistrationDefault;
549 }
550 else
551 {
552 type = mDNS_DomainTypeBrowse;
553 defaultType = mDNS_DomainTypeBrowseDefault;
554 }
555 interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
556
557 err = mDNS_GetDomains( gMDNSPtr, &obj->u.domain.question, type, NULL, interfaceID,
558 DNSServiceEnumerateDomainsCallBack_direct, obj );
559 require_noerr( err, exit );
560 obj->u.domain.questionActive = mDNStrue;
561
562 err = mDNS_GetDomains( gMDNSPtr, &obj->u.domain.defaultQuestion, defaultType, NULL, interfaceID,
563 DNSServiceEnumerateDomainsCallBack_direct, obj );
564 require_noerr( err, exit );
565 obj->u.domain.defaultQuestionActive = mDNStrue;
566
567 // Call back immediately with "local." since that is always available for all types of browsing.
568
569 flags = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd;
570 inCallBack( obj, flags, inInterfaceIndex, kDNSServiceErr_NoError, "local.", inContext );
571
572 // Success!
573
574 *outRef = obj;
575 obj = NULL;
576
577 exit:
578 if( obj )
579 {
580 DNSServiceRefDeallocate_direct( obj );
581 }
582 DNSServiceUnlock();
583 return( err );
584 }
585
586 //===========================================================================================================================
587 // DNSServiceEnumerateDomainsRelease_direct
588 //
589 // Warning: Assumes the mDNS platform lock is held.
590 //===========================================================================================================================
591
592 DEBUG_LOCAL void DNSServiceEnumerateDomainsRelease_direct( DNSServiceRef inRef )
593 {
594 OSStatus err;
595
596 check( inRef );
597
598 if( inRef->u.domain.questionActive )
599 {
600 err = mDNS_StopGetDomains( gMDNSPtr, &inRef->u.domain.question );
601 check_noerr( err );
602 }
603 if( inRef->u.domain.defaultQuestionActive )
604 {
605 err = mDNS_StopGetDomains( gMDNSPtr, &inRef->u.domain.defaultQuestion );
606 check_noerr( err );
607 }
608 free( inRef );
609 }
610
611 //===========================================================================================================================
612 // DNSServiceEnumerateDomainsCallBack_direct
613 //
614 // Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
615 //===========================================================================================================================
616
617 DEBUG_LOCAL void
618 DNSServiceEnumerateDomainsCallBack_direct(
619 mDNS * const inMDNS,
620 DNSQuestion * inQuestion,
621 const ResourceRecord * const inAnswer,
622 mDNSBool inAddRecord )
623 {
624 DNSServiceRef obj;
625 DNSServiceFlags flags;
626 uint32_t interfaceIndex;
627 char domain[ MAX_ESCAPED_DOMAIN_NAME ];
628
629 DEBUG_UNUSED( inMDNS );
630
631 check( inQuestion );
632 obj = (DNSServiceRef) inQuestion->QuestionContext;
633 check( obj );
634
635 flags = inAddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsNone;
636 if( inAddRecord )
637 {
638 if( inQuestion == &obj->u.domain.defaultQuestion )
639 {
640 flags |= kDNSServiceFlagsDefault;
641 }
642 }
643 interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, inAnswer->InterfaceID );
644 ConvertDomainNameToCString( &inAnswer->rdata->u.name, domain );
645
646 obj->u.domain.callback( obj, flags, interfaceIndex, kDNSServiceErr_NoError, domain, obj->context );
647 }
648
649 #if 0
650 #pragma mark -
651 #pragma mark == Service Registration ==
652 #endif
653
654 //===========================================================================================================================
655 // DNSServiceRegister_direct
656 //===========================================================================================================================
657
658 DNSServiceErrorType
659 DNSServiceRegister_direct(
660 DNSServiceRef * outRef,
661 DNSServiceFlags inFlags,
662 uint32_t inInterfaceIndex,
663 const char * inName,
664 const char * inType,
665 const char * inDomain,
666 const char * inHost,
667 uint16_t inPort,
668 uint16_t inTXTSize,
669 const void * inTXT,
670 DNSServiceRegisterReply inCallBack,
671 void * inContext )
672 {
673 DNSServiceErrorType err;
674 DNSServiceRef obj;
675 mDNSBool autoName;
676 domainname * host;
677 domainname tempHost;
678 mDNSBool ok;
679 size_t size;
680 domainlabel name;
681 domainname type;
682 domainname domain;
683 mDNSIPPort port;
684 mDNSInterfaceID interfaceID;
685
686 obj = NULL;
687 DNSServiceLock();
688 require_action( outRef, exit, err = kDNSServiceErr_BadReference );
689 require_action( ( inFlags == 0 ) || ( inFlags == kDNSServiceFlagsNoAutoRename ), exit, err = kDNSServiceErr_BadFlags );
690 autoName = !inName || ( *inName == '\0' );
691 require_action( !autoName || !( inFlags & kDNSServiceFlagsNoAutoRename ), exit, err = kDNSServiceErr_BadParam );
692 require_action( inType, exit, err = kDNSServiceErr_BadParam );
693 require_action( inTXT || ( inTXTSize == 0 ), exit, err = kDNSServiceErr_BadParam );
694 require_action( inCallBack || autoName, exit, err = kDNSServiceErr_BadParam );
695
696 // Convert all the input strings and make sure they are valid. Use the system name if auto-naming.
697
698 if( autoName )
699 {
700 name = gMDNSPtr->nicelabel;
701 }
702 else
703 {
704 ok = MakeDomainLabelFromLiteralString( &name, inName );
705 require_action( ok, exit, err = kDNSServiceErr_BadParam );
706 }
707
708 ok = MakeDomainNameFromDNSNameString( &type, inType ) != NULL;
709 require_action( ok, exit, err = kDNSServiceErr_BadParam );
710
711 if( !inDomain || ( *inDomain == '\0' ) )
712 {
713 inDomain = "local.";
714 }
715 ok = MakeDomainNameFromDNSNameString( &domain, inDomain ) != NULL;
716 require_action( ok, exit, err = kDNSServiceErr_BadParam );
717
718 // Set up the host name (if not using the default).
719
720 host = NULL;
721 if( inHost && ( *inHost != '\0' ) )
722 {
723 host = &tempHost;
724 ok = MakeDomainNameFromDNSNameString( host, inHost ) != NULL;
725 require_action( ok, exit, err = kDNSServiceErr_BadParam );
726
727 AppendDomainName( host, &domain );
728 }
729
730 // Allocate and initialize the object.
731
732 obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
733 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
734
735 obj->releaseCallBack = DNSServiceRegisterRelease_direct;
736 obj->context = inContext;
737 obj->u.reg.flags = 0;
738 if( autoName )
739 {
740 obj->u.reg.flags |= kDNSServiceRegisterFlagsAutoName;
741 }
742 if( !( inFlags & kDNSServiceFlagsNoAutoRename ) )
743 {
744 obj->u.reg.flags |= kDNSServiceRegisterFlagsRenameOnConflict;
745 }
746 obj->u.reg.callback = inCallBack;
747
748 // Allocate space for the records, including any extra space to handle an oversized TXT record.
749
750 size = sizeof( ServiceRecordSet );
751 if( inTXTSize > sizeof( RDataBody ) )
752 {
753 size += ( inTXTSize - sizeof( RDataBody ) );
754 }
755 obj->u.reg.set = (ServiceRecordSet *) calloc( 1, size );
756 require_action( obj->u.reg.set, exit, err = kDNSServiceErr_NoMemory );
757
758 obj->next = gDNSServiceRefList;
759 gDNSServiceRefList = obj;
760
761 // Register the service with mDNS.
762
763 port.NotAnInteger = inPort;
764 interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
765
766 err = mDNS_RegisterService( gMDNSPtr, obj->u.reg.set, &name, &type, &domain, host, port,
767 (const mDNSu8 *) inTXT, inTXTSize, NULL, 0, interfaceID, DNSServiceRegisterCallBack_direct, obj );
768 require_noerr( err, exit );
769
770 // Success!
771
772 *outRef = obj;
773 obj = NULL;
774
775 exit:
776 if( obj )
777 {
778 DNSServiceRegisterFree_direct( obj );
779 }
780 DNSServiceUnlock();
781 return( err );
782 }
783
784 //===========================================================================================================================
785 // DNSServiceRegisterRelease_direct
786 //
787 // Warning: Assumes the mDNS platform lock is held.
788 //===========================================================================================================================
789
790 DEBUG_LOCAL void DNSServiceRegisterRelease_direct( DNSServiceRef inRef )
791 {
792 mStatus err;
793
794 check( inRef );
795
796 // Deregister the service. If an error occurs (which should never happen), we have to assume that mDNS does not
797 // know about the registration and will not call us back with mStatus_MemFree so we free the memory here.
798 // Otherwise, mDNS will call us back with a mStatus_MemFree error code when it is safe for us to free the memory.
799
800 err = mDNS_DeregisterService( gMDNSPtr, inRef->u.reg.set );
801 check_noerr( err );
802 if( err != mStatus_NoError )
803 {
804 DNSServiceRegisterFree_direct( inRef );
805 }
806 }
807
808 //===========================================================================================================================
809 // DNSServiceRegisterCallBack_direct
810 //
811 // Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
812 //===========================================================================================================================
813
814 DEBUG_LOCAL void DNSServiceRegisterCallBack_direct( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult )
815 {
816 DNSServiceRef obj;
817 mDNSBool ok;
818 domainlabel name;
819 domainname type;
820 domainname domain;
821 char nameString[ MAX_DOMAIN_LABEL + 1 ];
822 char typeString[ MAX_ESCAPED_DOMAIN_NAME ];
823 char domainString[ MAX_ESCAPED_DOMAIN_NAME ];
824
825 DEBUG_UNUSED( inMDNS );
826 DEBUG_UNUSED( inSet );
827
828 obj = (DNSServiceRef) inSet->ServiceContext;
829 check( obj );
830
831 if( inResult == mStatus_NoError )
832 {
833 // Successful Registration.
834
835 if( obj->u.reg.callback )
836 {
837 ok = DeconstructServiceName( &inSet->RR_SRV.resrec.name, &name, &type, &domain );
838 check( ok );
839
840 ConvertDomainLabelToCString_unescaped( &name, nameString );
841 ConvertDomainNameToCString( &type, typeString );
842 ConvertDomainNameToCString( &domain, domainString );
843
844 obj->u.reg.callback( obj, 0, kDNSServiceErr_NoError, nameString, typeString, domainString, obj->context );
845 }
846 }
847 else if( inResult == mStatus_MemFree )
848 {
849 // If the AutoNameOnFree flag is set, it means we should re-register with the system name instead of freeing.
850 // Otherwise, mDNS is done with the memory so we can safely free it.
851
852 if( obj->u.reg.flags & kDNSServiceRegisterFlagsAutoNameOnFree )
853 {
854 obj->u.reg.flags &= ~kDNSServiceRegisterFlagsAutoNameOnFree;
855 obj->u.reg.name = gMDNSPtr->nicelabel;
856 inResult = mDNS_RenameAndReregisterService( gMDNSPtr, obj->u.reg.set, &obj->u.reg.name );
857 check_noerr( inResult );
858 }
859 if( inResult != mStatus_NoError )
860 {
861 DNSServiceRegisterFree_direct( obj );
862 }
863 }
864 else if( inResult == mStatus_NameConflict )
865 {
866 // Name conflict. If the auto renaming flags are enabled silently rename and re-register.
867 // Otherwise, mDNS will not send call us again with mStatus_MemFree so free the memory here.
868
869 if( obj->u.reg.flags & ( kDNSServiceRegisterFlagsAutoName | kDNSServiceRegisterFlagsRenameOnConflict ) )
870 {
871 inResult = mDNS_RenameAndReregisterService( gMDNSPtr, obj->u.reg.set, mDNSNULL );
872 }
873 if( inResult != mStatus_NoError )
874 {
875 if( obj->u.reg.callback )
876 {
877 obj->u.reg.callback( obj, 0, kDNSServiceErr_NameConflict, "", "", "", obj->context );
878 }
879 DNSServiceRegisterFree_direct( obj );
880 }
881 }
882 else
883 {
884 dlog( kDebugLevelNotice, "unknown register result (%d)\n", inResult );
885 if( obj->u.reg.callback )
886 {
887 obj->u.reg.callback( obj, 0, inResult, "", "", "", obj->context );
888 }
889 }
890 }
891
892 //===========================================================================================================================
893 // DNSServiceRegisterFree_direct
894 //===========================================================================================================================
895
896 DEBUG_LOCAL void DNSServiceRegisterFree_direct( DNSServiceRef inRef )
897 {
898 check( inRef );
899
900 if( inRef->u.reg.set )
901 {
902 // Note: Each "Extras" record is a "DNSServiceRef", which is just a syntactic wrapper for ExtraResourceRecord.
903 // This avoids the need for casting and simplifies access, but still allows the following loop to work correctly.
904
905 while( inRef->u.reg.set->Extras )
906 {
907 ExtraResourceRecord * extra;
908
909 extra = inRef->u.reg.set->Extras;
910 inRef->u.reg.set->Extras = extra->next;
911
912 free( extra );
913 }
914 free( inRef->u.reg.set );
915 }
916 free( inRef );
917 }
918
919 //===========================================================================================================================
920 // DNSServiceAddRecord_direct
921 //===========================================================================================================================
922
923 DNSServiceErrorType
924 DNSServiceAddRecord_direct(
925 DNSServiceRef inRef,
926 DNSRecordRef * outRecordRef,
927 DNSServiceFlags inFlags,
928 uint16_t inRRType,
929 uint16_t inRDataSize,
930 const void * inRData,
931 uint32_t inTTL )
932 {
933 DNSServiceErrorType err;
934 size_t size;
935 DNSRecordRef obj;
936 ExtraResourceRecord * extra;
937
938 obj = NULL;
939 DNSServiceLock();
940 require_action( inRef, exit, err = kDNSServiceErr_BadReference );
941 require_action( inRef->releaseCallBack == DNSServiceRegisterRelease_direct, exit, err = kDNSServiceErr_BadParam );
942 require_action( inRef->u.reg.set, exit, err = kDNSServiceErr_NotInitialized );
943 require_action( outRecordRef, exit, err = kDNSServiceErr_BadParam );
944 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
945 require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
946
947 // Allocate and initialize the record. Allocate oversized record space at the end of the record.
948
949 size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
950 obj = (DNSRecordRef) calloc( 1, ( kDNSRecordServiceFixedSize - sizeof( RDataBody ) ) + size );
951 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
952
953 extra = &obj->u.service.extra;
954 extra->r.resrec.rrtype = inRRType;
955 extra->r.resrec.rdlength = inRDataSize;
956 extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
957 memcpy( extra->r.rdatastorage.u.data, inRData, inRDataSize );
958
959 // Register the record with mDNS.
960
961 err = mDNS_AddRecordToService( gMDNSPtr, inRef->u.reg.set, extra, &extra->r.rdatastorage, inTTL );
962 require_noerr( err, exit );
963
964 // Success!
965
966 *outRecordRef = (DNSRecordRef) obj;
967 obj = NULL;
968
969 exit:
970 if( obj )
971 {
972 free( obj );
973 }
974 DNSServiceUnlock();
975 return( err );
976 }
977
978 //===========================================================================================================================
979 // DNSServiceUpdateRecord_direct
980 //===========================================================================================================================
981
982 DNSServiceErrorType
983 DNSServiceUpdateRecord_direct(
984 DNSServiceRef inRef,
985 DNSRecordRef inRecordRef,
986 DNSServiceFlags inFlags,
987 uint16_t inRDataSize,
988 const void * inRData,
989 uint32_t inTTL )
990 {
991 DNSServiceErrorType err;
992 AuthRecord * rr;
993 size_t size;
994 RData * rd;
995
996 rd = NULL;
997 DNSServiceLock();
998 require_action( inRef, exit, err = kDNSServiceErr_BadReference );
999 require_action( ( inRef->releaseCallBack == DNSServiceRegisterRelease_direct ) ||
1000 ( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct ),
1001 exit, err = kDNSServiceErr_BadParam );
1002 require_action( inRef->u.reg.set, exit, err = kDNSServiceErr_NotInitialized );
1003 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
1004 require_action( inRData, exit, err = kDNSServiceErr_BadParam );
1005
1006 // Get the embedded AuthRecord from the DNSRecordRef. Determine the type of DNSServiceRef from the releaseCallBack.
1007
1008 if( inRef->releaseCallBack == DNSServiceRegisterRelease_direct )
1009 {
1010 rr = inRecordRef ? &inRecordRef->u.service.extra.r : &inRef->u.reg.set->RR_TXT;
1011 }
1012 else if( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct )
1013 {
1014 require_action( inRecordRef, exit, err = kDNSServiceErr_BadReference );
1015 rr = &inRecordRef->u.connection.rr;
1016 }
1017 else
1018 {
1019 dlog( kDebugLevelError, DEBUG_NAME "trying to remove a DNSRecordRef with an unsupported DNSServiceRef\n" );
1020 err = kDNSServiceErr_Unsupported;
1021 goto exit;
1022 }
1023
1024 // Allocate and initialize the data. Allocate oversized data at the end of the record.
1025
1026 size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
1027 rd = (RData *) calloc( 1, ( sizeof( *rd ) - sizeof( RDataBody ) ) + size );
1028 require_action( rd, exit, err = kDNSServiceErr_NoMemory );
1029
1030 rd->MaxRDLength = (mDNSu16) size;
1031 memcpy( rd->u.data, inRData, inRDataSize );
1032
1033 // Update the record. A NULL record means to update the primary TXT record.
1034
1035 err = mDNS_Update( gMDNSPtr, rr, inTTL, inRDataSize, rd, DNSServiceUpdateRecordCallBack_direct );
1036 require_noerr( err, exit );
1037
1038 // Success!
1039
1040 rd = NULL;
1041
1042 exit:
1043 if( rd )
1044 {
1045 free( rd );
1046 }
1047 DNSServiceUnlock();
1048 return( err );
1049 }
1050
1051 //===========================================================================================================================
1052 // DNSServiceUpdateRecord_direct
1053 //
1054 // Warning: It is not safe to make any mDNS calls here.
1055 //===========================================================================================================================
1056
1057 DEBUG_LOCAL void DNSServiceUpdateRecordCallBack_direct( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldRData )
1058 {
1059 DEBUG_UNUSED( inMDNS );
1060
1061 check( inOldRData );
1062
1063 if( inOldRData != &inRR->rdatastorage )
1064 {
1065 free( inOldRData );
1066 }
1067 }
1068
1069 //===========================================================================================================================
1070 // DNSServiceRemoveRecord_direct
1071 //===========================================================================================================================
1072
1073 DNSServiceErrorType DNSServiceRemoveRecord_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags )
1074 {
1075 DNSServiceErrorType err;
1076
1077 DNSServiceLock();
1078 require_action( inRef, exit, err = kDNSServiceErr_BadReference );
1079 require_action( ( inRef->releaseCallBack == DNSServiceRegisterRelease_direct ) ||
1080 ( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct ),
1081 exit, err = kDNSServiceErr_BadParam );
1082 require_action( inRef->u.reg.set, exit, err = kDNSServiceErr_NotInitialized );
1083 require_action( inRecordRef, exit, err = kDNSServiceErr_BadParam );
1084 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
1085
1086 // Get the embedded AuthRecord from the DNSRecordRef. Determine the type of DNSServiceRef from the releaseCallBack.
1087
1088 if( inRef->releaseCallBack == DNSServiceRegisterRelease_direct )
1089 {
1090 err = mDNS_RemoveRecordFromService( gMDNSPtr, inRef->u.reg.set, &inRecordRef->u.service.extra );
1091 free( inRecordRef );
1092 require_noerr( err, exit );
1093 }
1094 else if( inRef->releaseCallBack == DNSServiceCreateConnectionRelease_direct )
1095 {
1096 mDNSBool freeRR;
1097
1098 inRecordRef = DNSServiceConnectionRecordRemove_direct( inRef, inRecordRef );
1099 require_action( inRecordRef, exit, err = kDNSServiceErr_BadParam );
1100
1101 freeRR = ( inRecordRef->u.connection.rr.resrec.RecordType != kDNSRecordTypeShared );
1102 err = mDNS_Deregister( gMDNSPtr, &inRecordRef->u.connection.rr );
1103 check_noerr( err );
1104 if( freeRR || ( err != mStatus_NoError ) )
1105 {
1106 free( inRecordRef );
1107 }
1108 }
1109 else
1110 {
1111 dlog( kDebugLevelError, DEBUG_NAME "trying to remove a DNSRecordRef with an unsupported DNSServiceRef\n" );
1112 err = kDNSServiceErr_Unsupported;
1113 goto exit;
1114 }
1115
1116 exit:
1117 DNSServiceUnlock();
1118 return( err );
1119 }
1120
1121 #if 0
1122 #pragma mark -
1123 #pragma mark == Service Discovery ==
1124 #endif
1125
1126 //===========================================================================================================================
1127 // DNSServiceBrowse_direct
1128 //===========================================================================================================================
1129
1130 DNSServiceErrorType
1131 DNSServiceBrowse_direct(
1132 DNSServiceRef * outRef,
1133 DNSServiceFlags inFlags,
1134 uint32_t inInterfaceIndex,
1135 const char * inType,
1136 const char * inDomain,
1137 DNSServiceBrowseReply inCallBack,
1138 void * inContext )
1139 {
1140 DNSServiceErrorType err;
1141 DNSServiceRef obj;
1142 mDNSBool ok;
1143 domainname type;
1144 domainname domain;
1145 mDNSInterfaceID interfaceID;
1146
1147 obj = NULL;
1148 DNSServiceLock();
1149 require_action( outRef, exit, err = kDNSServiceErr_BadReference );
1150 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
1151 require_action( inType, exit, err = kDNSServiceErr_BadParam );
1152 require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
1153
1154 // Convert the input strings and make sure they are valid.
1155
1156 ok = MakeDomainNameFromDNSNameString( &type, inType ) != NULL;
1157 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1158
1159 if( !inDomain || ( *inDomain == '\0' ) )
1160 {
1161 inDomain = "local.";
1162 }
1163 ok = MakeDomainNameFromDNSNameString( &domain, inDomain ) != NULL;
1164 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1165
1166 // Allocate and initialize the object.
1167
1168 obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
1169 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
1170
1171 obj->releaseCallBack = DNSServiceBrowseRelease_direct;
1172 obj->context = inContext;
1173 obj->u.browse.callback = inCallBack;
1174
1175 obj->next = gDNSServiceRefList;
1176 gDNSServiceRefList = obj;
1177
1178 // Start browsing.
1179
1180 interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
1181
1182 err = mDNS_StartBrowse( gMDNSPtr, &obj->u.browse.question, &type, &domain, interfaceID,
1183 DNSServiceBrowseCallBack_direct, obj );
1184 require_noerr( err, exit );
1185 obj->u.browse.questionActive = mDNStrue;
1186
1187 // Success!
1188
1189 *outRef = obj;
1190 obj = NULL;
1191
1192 exit:
1193 if( obj )
1194 {
1195 DNSServiceRefDeallocate_direct( obj );
1196 }
1197 DNSServiceUnlock();
1198 return( err );
1199 }
1200
1201 //===========================================================================================================================
1202 // DNSServiceBrowseRelease_direct
1203 //
1204 // Warning: Assumes the mDNS platform lock is held.
1205 //===========================================================================================================================
1206
1207 DEBUG_LOCAL void DNSServiceBrowseRelease_direct( DNSServiceRef inRef )
1208 {
1209 OSStatus err;
1210
1211 check( inRef );
1212
1213 if( inRef->u.browse.questionActive )
1214 {
1215 err = mDNS_StopBrowse( gMDNSPtr, &inRef->u.browse.question );
1216 check_noerr( err );
1217 }
1218 free( inRef );
1219 }
1220
1221 //===========================================================================================================================
1222 // DNSServiceBrowseCallBack_direct
1223 //
1224 // Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
1225 //===========================================================================================================================
1226
1227 DEBUG_LOCAL void
1228 DNSServiceBrowseCallBack_direct(
1229 mDNS * const inMDNS,
1230 DNSQuestion * inQuestion,
1231 const ResourceRecord * const inAnswer,
1232 mDNSBool inAddRecord )
1233 {
1234 DNSServiceRef obj;
1235 DNSServiceFlags flags;
1236 uint32_t interfaceIndex;
1237 mDNSBool ok;
1238 domainlabel name;
1239 domainname type;
1240 domainname domain;
1241 char nameString[ MAX_DOMAIN_LABEL + 1 ];
1242 char typeString[ MAX_ESCAPED_DOMAIN_NAME ];
1243 char domainString[ MAX_ESCAPED_DOMAIN_NAME ];
1244
1245 DEBUG_UNUSED( inMDNS );
1246 check( inQuestion );
1247 obj = (DNSServiceRef) inQuestion->QuestionContext;
1248 check( obj );
1249
1250 flags = inAddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsNone;
1251 interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, inAnswer->InterfaceID );
1252
1253 ok = DeconstructServiceName( &inAnswer->rdata->u.name, &name, &type, &domain );
1254 check( ok );
1255
1256 ConvertDomainLabelToCString_unescaped( &name, nameString );
1257 ConvertDomainNameToCString( &type, typeString );
1258 ConvertDomainNameToCString( &domain, domainString );
1259
1260 obj->u.browse.callback( obj, flags, interfaceIndex, kDNSServiceErr_NoError, nameString, typeString, domainString,
1261 obj->context );
1262 }
1263
1264 #if 0
1265 #pragma mark -
1266 #endif
1267
1268 //===========================================================================================================================
1269 // DNSServiceResolve_direct
1270 //===========================================================================================================================
1271
1272 DNSServiceErrorType
1273 DNSServiceResolve_direct(
1274 DNSServiceRef * outRef,
1275 DNSServiceFlags inFlags,
1276 uint32_t inInterfaceIndex,
1277 const char * inName,
1278 const char * inType,
1279 const char * inDomain,
1280 DNSServiceResolveReply inCallBack,
1281 void * inContext )
1282 {
1283 DNSServiceErrorType err;
1284 DNSServiceRef obj;
1285 mDNSBool ok;
1286 domainlabel name;
1287 domainname type;
1288 domainname domain;
1289 domainname fqdn;
1290 mDNSInterfaceID interfaceID;
1291 DNSQuestion * q;
1292
1293 obj = NULL;
1294 DNSServiceLock();
1295 dlog( kDebugLevelTrace, DEBUG_NAME "%s\n", __ROUTINE__ );
1296 require_action( outRef, exit, err = kDNSServiceErr_BadReference );
1297 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
1298 require_action( inName, exit, err = kDNSServiceErr_BadParam );
1299 require_action( inType, exit, err = kDNSServiceErr_BadParam );
1300 if( !inDomain || ( *inDomain == '\0' ) ) inDomain = "local.";
1301 require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
1302
1303 // Convert all the input strings and make sure they are valid.
1304
1305 ok = MakeDomainLabelFromLiteralString( &name, inName );
1306 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1307
1308 ok = MakeDomainNameFromDNSNameString( &type, inType ) != NULL;
1309 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1310
1311 ok = MakeDomainNameFromDNSNameString( &domain, inDomain ) != NULL;
1312 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1313
1314 ok = ConstructServiceName( &fqdn, &name, &type, &domain ) != NULL;
1315 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1316
1317 interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
1318
1319 // Allocate and initialize the object.
1320
1321 obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
1322 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
1323
1324 obj->releaseCallBack = DNSServiceResolveRelease_direct;
1325 obj->context = inContext;
1326 obj->u.resolve.flags = inFlags;
1327 obj->u.resolve.callback = inCallBack;
1328
1329 obj->next = gDNSServiceRefList;
1330 gDNSServiceRefList = obj;
1331
1332 // Start the SRV query.
1333
1334 q = &obj->u.resolve.srvQuestion;
1335 q->InterfaceID = interfaceID;
1336 AssignDomainName( q->qname, fqdn );
1337 q->qtype = kDNSType_SRV;
1338 q->qclass = kDNSClass_IN;
1339 q->QuestionCallback = DNSServiceResolveCallBack_direct;
1340 q->QuestionContext = obj;
1341
1342 err = mDNS_StartQuery( gMDNSPtr, q );
1343 require_noerr( err, exit );
1344 obj->u.resolve.srvQuestionActive = mDNStrue;
1345
1346 // Start the TXT query.
1347
1348 q = &obj->u.resolve.txtQuestion;
1349 q->InterfaceID = interfaceID;
1350 AssignDomainName( q->qname, fqdn );
1351 q->qtype = kDNSType_TXT;
1352 q->qclass = kDNSClass_IN;
1353 q->QuestionCallback = DNSServiceResolveCallBack_direct;
1354 q->QuestionContext = obj;
1355
1356 err = mDNS_StartQuery( gMDNSPtr, q );
1357 require_noerr( err, exit );
1358 obj->u.resolve.txtQuestionActive = mDNStrue;
1359
1360 // Success!
1361
1362 *outRef = obj;
1363 obj = NULL;
1364
1365 exit:
1366 if( obj )
1367 {
1368 DNSServiceRefDeallocate_direct( obj );
1369 }
1370 DNSServiceUnlock();
1371 return( err );
1372 }
1373
1374 //===========================================================================================================================
1375 // DNSServiceResolveRelease_direct
1376 //===========================================================================================================================
1377
1378 DEBUG_LOCAL void DNSServiceResolveRelease_direct( DNSServiceRef inRef )
1379 {
1380 OSStatus err;
1381
1382 check( inRef );
1383
1384 if( inRef->u.resolve.srvQuestionActive )
1385 {
1386 inRef->u.resolve.srvQuestionActive = mDNSfalse;
1387 err = mDNS_StopQuery( gMDNSPtr, &inRef->u.resolve.srvQuestion );
1388 check_noerr( err );
1389 }
1390 if( inRef->u.resolve.txtQuestionActive )
1391 {
1392 inRef->u.resolve.txtQuestionActive = mDNSfalse;
1393 err = mDNS_StopQuery( gMDNSPtr, &inRef->u.resolve.txtQuestion );
1394 check_noerr( err );
1395 }
1396 free( inRef );
1397 }
1398
1399 //===========================================================================================================================
1400 // DNSServiceResolveCallBack_direct
1401 //===========================================================================================================================
1402
1403 DEBUG_LOCAL void
1404 DNSServiceResolveCallBack_direct(
1405 mDNS * const inMDNS,
1406 DNSQuestion * inQuestion,
1407 const ResourceRecord * const inAnswer,
1408 mDNSBool inAddRecord )
1409 {
1410 DNSServiceRef obj;
1411 const ResourceRecord ** answer;
1412 uint32_t ifi;
1413 char fullName[ MAX_ESCAPED_DOMAIN_NAME ];
1414 char hostName[ MAX_ESCAPED_DOMAIN_NAME ];
1415 uint16_t port;
1416 const char * txt;
1417 uint16_t txtSize;
1418
1419 DEBUG_UNUSED( inMDNS );
1420
1421 check( inQuestion );
1422 obj = (DNSServiceRef) inQuestion->QuestionContext;
1423 check( obj );
1424 check( inAnswer );
1425
1426 // Select the answer based on the type.
1427
1428 if( inAnswer->rrtype == kDNSType_SRV ) answer = &obj->u.resolve.srvAnswer;
1429 else if( inAnswer->rrtype == kDNSType_TXT ) answer = &obj->u.resolve.txtAnswer;
1430 else
1431 {
1432 dlog( kDebugLevelError, DEBUG_NAME "%s: unexpected rrtype (%d)\n", __ROUTINE__, inAnswer->rrtype );
1433 goto exit;
1434 }
1435
1436 // If the record is being removed, invalidate the previous answer. Otherwise, update with the new answer.
1437
1438 if( !inAddRecord )
1439 {
1440 if( *answer == inAnswer ) *answer = NULL;
1441 goto exit;
1442 }
1443 *answer = inAnswer;
1444
1445 // Only deliver the result if we have both answers.
1446
1447 if( !obj->u.resolve.srvAnswer || !obj->u.resolve.txtAnswer )
1448 {
1449 goto exit;
1450 }
1451
1452 // Convert the results to the appropriate format and call the callback.
1453
1454 ifi = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, obj->u.resolve.srvAnswer->InterfaceID );
1455 ConvertDomainNameToCString( &obj->u.resolve.srvAnswer->name, fullName );
1456 ConvertDomainNameToCString( &obj->u.resolve.srvAnswer->rdata->u.srv.target, hostName );
1457 port = obj->u.resolve.srvAnswer->rdata->u.srv.port.NotAnInteger;
1458 txt = (const char *) obj->u.resolve.txtAnswer->rdata->u.txt.c;
1459 txtSize = obj->u.resolve.txtAnswer->rdlength;
1460
1461 obj->u.resolve.callback( obj, 0, ifi, kDNSServiceErr_NoError, fullName, hostName, port, txtSize, txt, obj->context );
1462
1463 exit:
1464 return;
1465 }
1466
1467 #if 0
1468 #pragma mark -
1469 #pragma mark == Special Purpose ==
1470 #endif
1471
1472 //===========================================================================================================================
1473 // DNSServiceCreateConnection_direct
1474 //===========================================================================================================================
1475
1476 DNSServiceErrorType DNSServiceCreateConnection_direct( DNSServiceRef *outRef )
1477 {
1478 OSStatus err;
1479 DNSServiceRef obj;
1480
1481 DNSServiceLock();
1482 require_action( outRef, exit, err = kDNSServiceErr_BadReference );
1483
1484 // Allocate and initialize the object.
1485
1486 obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
1487 require_action( obj, exit, err = kNoMemoryErr );
1488
1489 obj->releaseCallBack = DNSServiceCreateConnectionRelease_direct;
1490
1491 obj->next = gDNSServiceRefList;
1492 gDNSServiceRefList = obj;
1493
1494 // Success!
1495
1496 *outRef = obj;
1497 err = kNoErr;
1498
1499 exit:
1500 DNSServiceUnlock();
1501 return( err );
1502 }
1503
1504 //===========================================================================================================================
1505 // DNSServiceCreateConnectionRelease_direct
1506 //
1507 // Warning: Assumes the mDNS platform lock is held.
1508 //===========================================================================================================================
1509
1510 DEBUG_LOCAL void DNSServiceCreateConnectionRelease_direct( DNSServiceRef inRef )
1511 {
1512 check( inRef );
1513
1514 while( inRef->u.connection.records )
1515 {
1516 DNSRecordRef record;
1517 mStatus err;
1518 mDNSBool freeRR;
1519
1520 record = inRef->u.connection.records;
1521 inRef->u.connection.records = record->u.connection.next;
1522
1523 // If somebody will be looking at this object next, move the current ptr to the next object.
1524
1525 if( record == gDNSCurrentRecord )
1526 {
1527 dlog( kDebugLevelInfo, DEBUG_NAME "deleting gDNSCurrentRecord (%#p)\n", record );
1528 gDNSCurrentRecord = record->u.connection.next;
1529 }
1530
1531 freeRR = ( record->u.connection.rr.resrec.RecordType != kDNSRecordTypeShared );
1532 err = mDNS_Deregister( gMDNSPtr, &record->u.connection.rr );
1533 check_noerr( err );
1534 if( freeRR || ( err != mStatus_NoError ) )
1535 {
1536 free( record );
1537 }
1538 }
1539 free( inRef );
1540 }
1541
1542 //===========================================================================================================================
1543 // DNSServiceConnectionRecordRemove_direct
1544 //
1545 // Warning: Assumes the mDNS platform lock is held.
1546 //===========================================================================================================================
1547
1548 DEBUG_LOCAL DNSRecordRef DNSServiceConnectionRecordRemove_direct( DNSServiceRef inRef, DNSRecordRef inRecordRef )
1549 {
1550 DNSRecordRef * p;
1551
1552 for( p = &inRef->u.connection.records; *p; p = &( *p )->u.connection.next )
1553 {
1554 if( *p == inRecordRef )
1555 {
1556 break;
1557 }
1558 }
1559 inRecordRef = *p;
1560 if( inRecordRef )
1561 {
1562 *p = inRecordRef->u.connection.next;
1563
1564 // If somebody will be looking at this object next, move the current ptr to the next object.
1565
1566 if( inRecordRef == gDNSCurrentRecord )
1567 {
1568 gDNSCurrentRecord = inRecordRef->u.connection.next;
1569 }
1570 }
1571 return( inRecordRef );
1572 }
1573
1574 //===========================================================================================================================
1575 // DNSServiceRegisterRecord_direct
1576 //===========================================================================================================================
1577
1578 DNSServiceErrorType
1579 DNSServiceRegisterRecord_direct(
1580 DNSServiceRef inRef,
1581 DNSRecordRef * outRecordRef,
1582 DNSServiceFlags inFlags,
1583 uint32_t inInterfaceIndex,
1584 const char * inName,
1585 uint16_t inRRType,
1586 uint16_t inRRClass,
1587 uint16_t inRDataSize,
1588 const void * inRData,
1589 uint32_t inTTL,
1590 DNSServiceRegisterRecordReply inCallBack,
1591 void * inContext )
1592 {
1593 DNSServiceErrorType err;
1594 size_t size;
1595 DNSRecordRef obj;
1596 AuthRecord * rr;
1597 mDNSBool ok;
1598
1599 obj = NULL;
1600 DNSServiceLock();
1601 require_action( inRef, exit, err = kDNSServiceErr_BadReference );
1602 require_action( outRecordRef, exit, err = kDNSServiceErr_BadParam );
1603 require_action( ( inFlags == kDNSServiceFlagsShared ) ||
1604 ( inFlags == kDNSServiceFlagsUnique ),
1605 exit, err = kDNSServiceErr_BadFlags );
1606 require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
1607 require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
1608
1609 // Allocate and initialize the record. Allocate oversized record space at the end of the record.
1610
1611 size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
1612 obj = (DNSRecordRef) calloc( 1, ( kDNSRecordConnectionFixedSize - sizeof( RDataBody ) ) + size );
1613 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
1614
1615 obj->u.connection.owner = inRef;
1616 obj->u.connection.callback = inCallBack;
1617 obj->u.connection.context = inContext;
1618
1619 obj->u.connection.next = inRef->u.connection.records;
1620 inRef->u.connection.records = obj;
1621
1622 rr = &obj->u.connection.rr;
1623 rr->resrec.RecordType = (mDNSu8)( ( inFlags == kDNSServiceFlagsShared ) ? kDNSRecordTypeShared : kDNSRecordTypeUnique );
1624 rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
1625
1626 ok = MakeDomainNameFromDNSNameString( &rr->resrec.name, inName ) != NULL;
1627 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1628
1629 rr->resrec.rrtype = inRRType;
1630 rr->resrec.rrclass = inRRClass;
1631 rr->resrec.rroriginalttl = inTTL;
1632 rr->resrec.rdlength = inRDataSize;
1633 rr->resrec.rdata = &rr->rdatastorage;
1634 rr->resrec.rdata->MaxRDLength = inRDataSize;
1635 memcpy( rr->resrec.rdata->u.data, inRData, inRDataSize );
1636 rr->RecordContext = obj;
1637 rr->RecordCallback = DNSServiceRegisterRecordCallBack_direct;
1638
1639 // Register the record with mDNS.
1640
1641 err = mDNS_Register( gMDNSPtr, rr );
1642 require_noerr( err, exit );
1643
1644 // Success!
1645
1646 *outRecordRef = obj;
1647 obj = NULL;
1648
1649 exit:
1650 if( obj )
1651 {
1652 DNSServiceConnectionRecordRemove_direct( inRef, obj );
1653 free( obj );
1654 }
1655 DNSServiceUnlock();
1656 return( err );
1657 }
1658
1659 //===========================================================================================================================
1660 // DNSServiceRegisterRecord_direct
1661 //
1662 // Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
1663 //===========================================================================================================================
1664
1665 DEBUG_LOCAL void DNSServiceRegisterRecordCallBack_direct( mDNS * const inMDNS, AuthRecord * const inRR, mStatus inResult )
1666 {
1667 DNSRecordRef obj;
1668
1669 DEBUG_UNUSED( inMDNS );
1670
1671 check( inRR );
1672 obj = (DNSRecordRef) inRR->RecordContext;
1673 check( obj );
1674
1675 if( inResult == mStatus_MemFree )
1676 {
1677 DNSServiceConnectionRecordRemove_direct( obj->u.connection.owner, obj );
1678 free( inRR );
1679 }
1680 else
1681 {
1682 obj->u.connection.callback( obj->u.connection.owner, obj, 0, inResult, obj->u.connection.context );
1683 }
1684 }
1685
1686 //===========================================================================================================================
1687 // DNSServiceQueryRecord_direct
1688 //===========================================================================================================================
1689
1690 DNSServiceErrorType
1691 DNSServiceQueryRecord_direct(
1692 DNSServiceRef * outRef,
1693 DNSServiceFlags inFlags,
1694 uint32_t inInterfaceIndex,
1695 const char * inName,
1696 uint16_t inRRType,
1697 uint16_t inRRClass,
1698 DNSServiceQueryRecordReply inCallBack,
1699 void * inContext )
1700 {
1701 DNSServiceErrorType err;
1702 DNSServiceRef obj;
1703 DNSQuestion * q;
1704 mDNSBool ok;
1705
1706 obj = NULL;
1707 DNSServiceLock();
1708 require_action( outRef, exit, err = kDNSServiceErr_BadParam );
1709 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
1710 require_action( inName, exit, err = kDNSServiceErr_BadParam );
1711 require_action( inCallBack, exit, err = kDNSServiceErr_BadParam );
1712
1713 // Allocate and initialize the object.
1714
1715 obj = (DNSServiceRef) calloc( 1, sizeof( *obj ) );
1716 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
1717
1718 obj->releaseCallBack = DNSServiceQueryRecordRelease_direct;
1719 obj->context = inContext;
1720 obj->u.query.callback = inCallBack;
1721
1722 q = &obj->u.query.question;
1723 q->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
1724 ok = MakeDomainNameFromDNSNameString( &q->qname, inName ) != NULL;
1725 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1726 q->qtype = inRRType;
1727 q->qclass = inRRClass;
1728 q->QuestionCallback = DNSServiceQueryRecordCallBack_direct;
1729 q->QuestionContext = obj;
1730
1731 obj->next = gDNSServiceRefList;
1732 gDNSServiceRefList = obj;
1733
1734 // Start the query with mDNS.
1735
1736 err = mDNS_StartQuery( gMDNSPtr, q );
1737 require_noerr( err, exit );
1738 obj->u.query.questionActive = mDNStrue;
1739
1740 // Success!
1741
1742 *outRef = obj;
1743 obj = NULL;
1744
1745 exit:
1746 if( obj )
1747 {
1748 DNSServiceRefDeallocate_direct( obj );
1749 }
1750 DNSServiceUnlock();
1751 return( err );
1752 }
1753
1754 //===========================================================================================================================
1755 // DNSServiceQueryRecordRelease_direct
1756 //
1757 // Warning: Assumes the mDNS platform lock is held.
1758 //===========================================================================================================================
1759
1760 DEBUG_LOCAL void DNSServiceQueryRecordRelease_direct( DNSServiceRef inRef )
1761 {
1762 OSStatus err;
1763
1764 check( inRef );
1765
1766 if( inRef->u.query.questionActive )
1767 {
1768 err = mDNS_StopQuery( gMDNSPtr, &inRef->u.query.question );
1769 check_noerr( err );
1770 }
1771 free( inRef );
1772 }
1773
1774 //===========================================================================================================================
1775 // DNSServiceQueryRecordCallBack_direct
1776 //
1777 // Warning: Assumes the mDNS platform lock is held (held by mDNS before invoking this callback).
1778 //===========================================================================================================================
1779
1780 DEBUG_LOCAL void
1781 DNSServiceQueryRecordCallBack_direct(
1782 mDNS * const inMDNS,
1783 DNSQuestion * inQuestion,
1784 const ResourceRecord * const inAnswer,
1785 mDNSBool inAddRecord )
1786 {
1787 DNSServiceRef obj;
1788 DNSServiceFlags flags;
1789 uint32_t interfaceIndex;
1790 char name[ MAX_ESCAPED_DOMAIN_NAME ];
1791
1792 DEBUG_UNUSED( inMDNS );
1793
1794 check( inQuestion );
1795 obj = (DNSServiceRef) inQuestion->QuestionContext;
1796 check( obj );
1797 check( inAnswer );
1798
1799 flags = inAddRecord ? kDNSServiceFlagsAdd : kDNSServiceFlagsNone;
1800 interfaceIndex = mDNSPlatformInterfaceIndexfromInterfaceID( &gMDNS, inAnswer->InterfaceID );
1801 ConvertDomainNameToCString( &inAnswer->name, name );
1802 obj->u.query.callback( obj, flags, interfaceIndex, kDNSServiceErr_NoError, name, inAnswer->rrtype, inAnswer->rrclass,
1803 inAnswer->rdlength, &inAnswer->rdata->u, inAddRecord ? inAnswer->rroriginalttl : 0, obj->context );
1804 }
1805
1806 //===========================================================================================================================
1807 // DNSServiceReconfirmRecord_direct
1808 //===========================================================================================================================
1809
1810 void
1811 DNSServiceReconfirmRecord_direct(
1812 DNSServiceFlags inFlags,
1813 uint32_t inInterfaceIndex,
1814 const char * inName,
1815 uint16_t inRRType,
1816 uint16_t inRRClass,
1817 uint16_t inRDataSize,
1818 const void * inRData )
1819 {
1820 DNSServiceErrorType err;
1821 size_t size;
1822 AuthRecord * rr;
1823 mDNSBool ok;
1824
1825 rr = NULL;
1826 DNSServiceLock();
1827 require_action( inFlags == 0, exit, err = kDNSServiceErr_BadFlags );
1828 require_action( inName, exit, err = kDNSServiceErr_BadParam );
1829 require_action( inRData && ( inRDataSize > 0 ), exit, err = kDNSServiceErr_BadParam );
1830
1831 size = ( inRDataSize > sizeof( RDataBody ) ) ? inRDataSize : sizeof( RDataBody );
1832 rr = (AuthRecord *) calloc( 1, ( sizeof( *rr ) - sizeof( RDataBody ) ) + size );
1833 require_action( rr, exit, err = kDNSServiceErr_NoMemory );
1834
1835 rr->resrec.RecordType = (mDNSu8)( ( inFlags == kDNSServiceFlagsShared ) ? kDNSRecordTypeShared : kDNSRecordTypeUnique );
1836 rr->resrec.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex( gMDNSPtr, inInterfaceIndex );
1837
1838 ok = MakeDomainNameFromDNSNameString( &rr->resrec.name, inName ) != NULL;
1839 require_action( ok, exit, err = kDNSServiceErr_BadParam );
1840
1841 rr->resrec.rrtype = inRRType;
1842 rr->resrec.rrclass = inRRClass;
1843 rr->resrec.rdlength = inRDataSize;
1844 rr->resrec.rdata = &rr->rdatastorage;
1845 rr->resrec.rdata->MaxRDLength = inRDataSize;
1846 memcpy( rr->resrec.rdata->u.data, inRData, inRDataSize );
1847
1848 err = mDNS_ReconfirmByValue( gMDNSPtr, &rr->resrec );
1849 check( ( err == mStatus_BadReferenceErr ) || ( err == mStatus_NoError ) );
1850
1851 exit:
1852 if( rr )
1853 {
1854 free( rr );
1855 }
1856 DNSServiceUnlock();
1857 }
1858
1859 #ifdef __cplusplus
1860 }
1861 #endif
1862
1863 #endif // DNS_SD_DIRECT_ENABLED