2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
28 Revision 1.3 2004/05/11 03:08:53 bradley
29 Updated TXT Record API based on latest proposal. This still includes dynamic TXT record building for
30 a final CVS snapshot for private libraries before this functionality is removed from the public API.
32 Revision 1.2 2004/05/03 10:34:24 bradley
33 Implemented preliminary version of the TXTRecord API.
35 Revision 1.1 2004/01/30 02:45:21 bradley
36 High-level implementation of the DNS-SD API. Supports both "direct" (compiled-in mDNSCore) and "client"
37 (IPC<->service) usage. Conditionals can exclude either "direct" or "client" to reduce code size.
46 #include "CommonServices.h"
47 #include "DebugServices.h"
49 #include "DNSSDDirect.h"
50 #include "RMxClient.h"
58 //===========================================================================================================================
60 //===========================================================================================================================
62 #define DEBUG_NAME "[DNS-SD] "
64 //===========================================================================================================================
66 //===========================================================================================================================
68 DEBUG_LOCAL
int DomainEndsInDot( const char *dom
);
70 //===========================================================================================================================
72 //===========================================================================================================================
74 #if( DNS_SD_CLIENT_ENABLED )
75 const char * gDNSSDServer
= NULL
;
76 DEBUG_LOCAL
bool gDNSSDServerCompatible
= false;
80 #pragma mark == General ==
83 //===========================================================================================================================
84 // DNSServiceInitialize
85 //===========================================================================================================================
87 DNSServiceErrorType
DNSServiceInitialize( DNSServiceInitializeFlags inFlags
, int inCacheEntryCount
)
89 DNSServiceErrorType err
;
91 #if( DNS_SD_CLIENT_ENABLED )
92 err
= RMxClientInitialize();
95 // Perform a version check to see if the server is compatible.
97 if( !( inFlags
& kDNSServiceInitializeFlagsNoServerCheck
) )
99 err
= DNSServiceCheckVersion();
107 // Version check disabled so just assume the server is compatible.
109 gDNSSDServerCompatible
= true;
115 #if( DNS_SD_DIRECT_ENABLED )
116 #if( DNS_SD_CLIENT_ENABLED )
117 dlog( kDebugLevelNotice
, DEBUG_NAME
"server missing or incompatible...falling back to direct implementation\n" );
119 err
= DNSServiceInitialize_direct( inFlags
, inCacheEntryCount
);
122 DEBUG_UNUSED( inFlags
);
123 DEBUG_UNUSED( inCacheEntryCount
);
125 err
= kUnsupportedErr
;
133 //===========================================================================================================================
134 // DNSServiceFinalize
135 //===========================================================================================================================
137 void DNSServiceFinalize( void )
139 #if( DNS_SD_CLIENT_ENABLED )
143 #if( DNS_SD_DIRECT_ENABLED )
144 DNSServiceFinalize_direct();
148 //===========================================================================================================================
149 // DNSServiceCheckVersion
150 //===========================================================================================================================
152 DNSServiceErrorType
DNSServiceCheckVersion( void )
154 DNSServiceErrorType err
;
156 #if( DNS_SD_CLIENT_ENABLED )
157 err
= DNSServiceCheckVersion_client( gDNSSDServer
);
160 gDNSSDServerCompatible
= true;
163 err
= kUnsupportedErr
;
171 #pragma mark == Properties ==
174 //===========================================================================================================================
175 // DNSServiceCopyProperty
176 //===========================================================================================================================
178 DNSServiceErrorType
DNSServiceCopyProperty( DNSPropertyCode inCode
, DNSPropertyData
*outData
)
180 DNSServiceErrorType err
;
182 #if( DNS_SD_CLIENT_ENABLED )
183 if( gDNSSDServerCompatible
)
185 err
= DNSServiceCopyProperty_client( gDNSSDServer
, inCode
, outData
);
189 DEBUG_UNUSED( inCode
);
190 DEBUG_UNUSED( outData
);
193 #if( DNS_SD_DIRECT_ENABLED )
194 err
= kUnsupportedErr
;
197 err
= kUnsupportedErr
;
205 //===========================================================================================================================
206 // DNSServiceReleaseProperty
207 //===========================================================================================================================
209 DNSServiceErrorType
DNSServiceReleaseProperty( DNSPropertyData
*inData
)
211 DNSServiceErrorType err
;
213 #if( DNS_SD_CLIENT_ENABLED )
214 if( gDNSSDServerCompatible
)
216 err
= DNSServiceReleaseProperty_client( inData
);
220 DEBUG_UNUSED( inData
);
223 #if( DNS_SD_DIRECT_ENABLED )
224 err
= kUnsupportedErr
;
227 err
= kUnsupportedErr
;
237 #pragma mark == Unix Domain Socket Access ==
240 //===========================================================================================================================
241 // DNSServiceRefSockFD
242 //===========================================================================================================================
244 int DNSServiceRefSockFD( DNSServiceRef inRef
)
246 DEBUG_UNUSED( inRef
);
248 dlog( kDebugLevelError
, "DNSServiceRefSockFD is not supported\n" );
252 //===========================================================================================================================
253 // DNSServiceProcessResult
254 //===========================================================================================================================
256 DNSServiceErrorType
DNSServiceProcessResult( DNSServiceRef inRef
)
258 DEBUG_UNUSED( inRef
);
260 dlog( kDebugLevelError
, "DNSServiceProcessResult is not supported\n" );
261 return( kDNSServiceErr_Unsupported
);
264 //===========================================================================================================================
265 // DNSServiceRefDeallocate
266 //===========================================================================================================================
268 void DNSServiceRefDeallocate( DNSServiceRef inRef
)
270 #if( DNS_SD_CLIENT_ENABLED )
271 if( gDNSSDServerCompatible
)
273 DNSServiceRefDeallocate_client( inRef
);
278 #if( DNS_SD_DIRECT_ENABLED )
279 DNSServiceRefDeallocate_direct( inRef
);
282 DEBUG_UNUSED( inRef
);
293 #pragma mark == Domain Enumeration ==
296 //===========================================================================================================================
297 // DNSServiceEnumerateDomains
298 //===========================================================================================================================
301 DNSServiceEnumerateDomains(
302 DNSServiceRef
* outRef
,
303 const DNSServiceFlags inFlags
,
304 const uint32_t inInterfaceIndex
,
305 const DNSServiceDomainEnumReply inCallBack
,
308 DNSServiceErrorType err
;
310 #if( DNS_SD_CLIENT_ENABLED )
311 if( gDNSSDServerCompatible
)
313 err
= DNSServiceEnumerateDomains_client( outRef
, gDNSSDServer
, inFlags
, inInterfaceIndex
, inCallBack
, inContext
);
318 #if( DNS_SD_DIRECT_ENABLED )
319 err
= DNSServiceEnumerateDomains_direct( outRef
, inFlags
, inInterfaceIndex
, inCallBack
, inContext
);
322 DEBUG_UNUSED( outRef
);
323 DEBUG_UNUSED( inFlags
);
324 DEBUG_UNUSED( inInterfaceIndex
);
325 DEBUG_UNUSED( inCallBack
);
326 DEBUG_UNUSED( inContext
);
328 err
= kUnsupportedErr
;
338 #pragma mark == Service Registration ==
341 //===========================================================================================================================
342 // DNSServiceRegister
343 //===========================================================================================================================
347 DNSServiceRef
* outRef
,
348 DNSServiceFlags inFlags
,
349 uint32_t inInterfaceIndex
,
352 const char * inDomain
,
357 DNSServiceRegisterReply inCallBack
,
360 DNSServiceErrorType err
;
362 #if( DNS_SD_CLIENT_ENABLED )
363 if( gDNSSDServerCompatible
)
365 err
= DNSServiceRegister_client( outRef
, gDNSSDServer
, inFlags
, inInterfaceIndex
, inName
, inType
, inDomain
,
366 inHost
, inPort
, inTXTSize
, inTXT
, inCallBack
, inContext
);
371 #if( DNS_SD_DIRECT_ENABLED )
372 err
= DNSServiceRegister_direct( outRef
, inFlags
, inInterfaceIndex
, inName
, inType
, inDomain
, inHost
, inPort
,
373 inTXTSize
, inTXT
, inCallBack
, inContext
);
376 DEBUG_UNUSED( outRef
);
377 DEBUG_UNUSED( inFlags
);
378 DEBUG_UNUSED( inInterfaceIndex
);
379 DEBUG_UNUSED( inName
);
380 DEBUG_UNUSED( inType
);
381 DEBUG_UNUSED( inDomain
);
382 DEBUG_UNUSED( inHost
);
383 DEBUG_UNUSED( inPort
);
384 DEBUG_UNUSED( inTXTSize
);
385 DEBUG_UNUSED( inTXT
);
386 DEBUG_UNUSED( inCallBack
);
387 DEBUG_UNUSED( inContext
);
389 err
= kUnsupportedErr
;
397 //===========================================================================================================================
398 // DNSServiceAddRecord
399 //===========================================================================================================================
404 DNSRecordRef
* outRecordRef
,
405 DNSServiceFlags inFlags
,
407 uint16_t inRDataSize
,
408 const void * inRData
,
411 DNSServiceErrorType err
;
413 #if( DNS_SD_CLIENT_ENABLED )
414 if( gDNSSDServerCompatible
)
416 err
= DNSServiceAddRecord_client( inRef
, outRecordRef
, inFlags
, inRRType
, inRDataSize
, inRData
, inTTL
);
421 #if( DNS_SD_DIRECT_ENABLED )
422 err
= DNSServiceAddRecord_direct( inRef
, outRecordRef
, inFlags
, inRRType
, inRDataSize
, inRData
, inTTL
);
425 DEBUG_UNUSED( inRef
);
426 DEBUG_UNUSED( outRecordRef
);
427 DEBUG_UNUSED( inFlags
);
428 DEBUG_UNUSED( inRRType
);
429 DEBUG_UNUSED( inRDataSize
);
430 DEBUG_UNUSED( inRData
);
431 DEBUG_UNUSED( inTTL
);
433 err
= kUnsupportedErr
;
441 //===========================================================================================================================
442 // DNSServiceUpdateRecord
443 //===========================================================================================================================
446 DNSServiceUpdateRecord(
448 DNSRecordRef inRecordRef
,
449 DNSServiceFlags inFlags
,
450 uint16_t inRDataSize
,
451 const void * inRData
,
454 DNSServiceErrorType err
;
456 #if( DNS_SD_CLIENT_ENABLED )
457 if( gDNSSDServerCompatible
)
459 err
= DNSServiceUpdateRecord_client( inRef
, inRecordRef
, inFlags
, inRDataSize
, inRData
, inTTL
);
464 #if( DNS_SD_DIRECT_ENABLED )
465 err
= DNSServiceUpdateRecord_direct( inRef
, inRecordRef
, inFlags
, inRDataSize
, inRData
, inTTL
);
468 DEBUG_UNUSED( inRef
);
469 DEBUG_UNUSED( inRecordRef
);
470 DEBUG_UNUSED( inFlags
);
471 DEBUG_UNUSED( inRDataSize
);
472 DEBUG_UNUSED( inRData
);
473 DEBUG_UNUSED( inTTL
);
475 err
= kUnsupportedErr
;
483 //===========================================================================================================================
484 // DNSServiceRemoveRecord
485 //===========================================================================================================================
487 DNSServiceErrorType
DNSServiceRemoveRecord( DNSServiceRef inRef
, DNSRecordRef inRecordRef
, DNSServiceFlags inFlags
)
489 DNSServiceErrorType err
;
491 #if( DNS_SD_CLIENT_ENABLED )
492 if( gDNSSDServerCompatible
)
494 err
= DNSServiceRemoveRecord_client( inRef
, inRecordRef
, inFlags
);
499 #if( DNS_SD_DIRECT_ENABLED )
500 err
= DNSServiceRemoveRecord_direct( inRef
, inRecordRef
, inFlags
);
503 DEBUG_UNUSED( inRef
);
504 DEBUG_UNUSED( inRecordRef
);
505 DEBUG_UNUSED( inFlags
);
507 err
= kUnsupportedErr
;
517 #pragma mark == Service Discovery ==
520 //===========================================================================================================================
522 //===========================================================================================================================
526 DNSServiceRef
* outRef
,
527 DNSServiceFlags inFlags
,
528 uint32_t inInterfaceIndex
,
530 const char * inDomain
,
531 DNSServiceBrowseReply inCallBack
,
534 DNSServiceErrorType err
;
536 #if( DNS_SD_CLIENT_ENABLED )
537 if( gDNSSDServerCompatible
)
539 err
= DNSServiceBrowse_client( outRef
, gDNSSDServer
, inFlags
, inInterfaceIndex
, inType
, inDomain
,
540 inCallBack
, inContext
);
545 #if( DNS_SD_DIRECT_ENABLED )
546 err
= DNSServiceBrowse_direct( outRef
, inFlags
, inInterfaceIndex
, inType
, inDomain
, inCallBack
, inContext
);
549 DEBUG_UNUSED( outRef
);
550 DEBUG_UNUSED( inFlags
);
551 DEBUG_UNUSED( inInterfaceIndex
);
552 DEBUG_UNUSED( inType
);
553 DEBUG_UNUSED( inDomain
);
554 DEBUG_UNUSED( inCallBack
);
555 DEBUG_UNUSED( inContext
);
557 err
= kUnsupportedErr
;
565 //===========================================================================================================================
567 //===========================================================================================================================
571 DNSServiceRef
* outRef
,
572 DNSServiceFlags inFlags
,
573 uint32_t inInterfaceIndex
,
576 const char * inDomain
,
577 DNSServiceResolveReply inCallBack
,
580 DNSServiceErrorType err
;
582 #if( DNS_SD_CLIENT_ENABLED )
583 if( gDNSSDServerCompatible
)
585 err
= DNSServiceResolve_client( outRef
, gDNSSDServer
, inFlags
, inInterfaceIndex
, inName
, inType
, inDomain
,
586 inCallBack
, inContext
);
591 #if( DNS_SD_DIRECT_ENABLED )
592 err
= DNSServiceResolve_direct( outRef
, inFlags
, inInterfaceIndex
, inName
, inType
, inDomain
, inCallBack
, inContext
);
595 DEBUG_UNUSED( outRef
);
596 DEBUG_UNUSED( inFlags
);
597 DEBUG_UNUSED( inInterfaceIndex
);
598 DEBUG_UNUSED( inName
);
599 DEBUG_UNUSED( inType
);
600 DEBUG_UNUSED( inDomain
);
601 DEBUG_UNUSED( inCallBack
);
602 DEBUG_UNUSED( inContext
);
604 err
= kUnsupportedErr
;
614 #pragma mark == Special Purpose ==
617 //===========================================================================================================================
618 // DNSServiceConstructFullName
620 // Copied from dnssd_clientstub.c with minimal changes to support NULL/empty name, type, and domain.
621 //===========================================================================================================================
623 int DNSServiceConstructFullName( char *fullName
, const char *service
, const char *regtype
, const char *domain
)
628 const char *s
= service
;
629 const char *r
= regtype
;
630 const char *d
= domain
;
632 if (service
&& *service
)
636 c
= (unsigned char) *s
++;
637 if (c
== '.' || (c
== '\\')) *fn
++ = '\\'; // escape dot and backslash literals
638 else if (c
<= ' ') // escape non-printable characters
641 *fn
++ = (char) ('0' + (c
/ 100));
642 *fn
++ = (char) ('0' + (c
/ 10) % 10);
643 c
= (unsigned char)('0' + (c
% 10));
650 if (regtype
&& *regtype
)
652 len
= strlen(regtype
);
653 if (DomainEndsInDot(regtype
)) len
--;
654 if (len
< 4) return -1; // regtype must end in _udp or _tcp
655 if (strncmp((regtype
+ len
- 4), "_tcp", 4) && strncmp((regtype
+ len
- 4), "_udp", 4)) return -1;
658 if (!DomainEndsInDot(regtype
)) *fn
++ = '.';
661 if (!domain
|| !(*domain
))
666 len
= strlen(domain
);
670 if (!DomainEndsInDot(domain
)) *fn
++ = '.';
675 //===========================================================================================================================
676 // DNSServiceCreateConnection
677 //===========================================================================================================================
679 DNSServiceErrorType
DNSServiceCreateConnection( DNSServiceRef
*outRef
)
681 DNSServiceErrorType err
;
683 #if( DNS_SD_CLIENT_ENABLED )
684 if( gDNSSDServerCompatible
)
686 err
= DNSServiceCreateConnection_client( outRef
, gDNSSDServer
);
691 #if( DNS_SD_DIRECT_ENABLED )
692 err
= DNSServiceCreateConnection_direct( outRef
);
695 DEBUG_UNUSED( outRef
);
697 err
= kUnsupportedErr
;
705 //===========================================================================================================================
706 // DNSServiceRegisterRecord
707 //===========================================================================================================================
710 DNSServiceRegisterRecord(
712 DNSRecordRef
* outRecordRef
,
713 DNSServiceFlags inFlags
,
714 uint32_t inInterfaceIndex
,
718 uint16_t inRDataSize
,
719 const void * inRData
,
721 DNSServiceRegisterRecordReply inCallBack
,
724 DNSServiceErrorType err
;
726 #if( DNS_SD_CLIENT_ENABLED )
727 if( gDNSSDServerCompatible
)
729 err
= DNSServiceRegisterRecord_client( inRef
, outRecordRef
, inFlags
, inInterfaceIndex
, inName
,
730 inRRType
, inRRClass
, inRDataSize
, inRData
, inTTL
, inCallBack
, inContext
);
735 #if( DNS_SD_DIRECT_ENABLED )
736 err
= DNSServiceRegisterRecord_direct( inRef
, outRecordRef
, inFlags
, inInterfaceIndex
, inName
,
737 inRRType
, inRRClass
, inRDataSize
, inRData
, inTTL
, inCallBack
, inContext
);
740 DEBUG_UNUSED( inRef
);
741 DEBUG_UNUSED( outRecordRef
);
742 DEBUG_UNUSED( inFlags
);
743 DEBUG_UNUSED( inInterfaceIndex
);
744 DEBUG_UNUSED( inName
);
745 DEBUG_UNUSED( inRRType
);
746 DEBUG_UNUSED( inRRClass
);
747 DEBUG_UNUSED( inRDataSize
);
748 DEBUG_UNUSED( inRData
);
749 DEBUG_UNUSED( inTTL
);
750 DEBUG_UNUSED( inCallBack
);
751 DEBUG_UNUSED( inContext
);
753 err
= kUnsupportedErr
;
761 //===========================================================================================================================
762 // DNSServiceQueryRecord
763 //===========================================================================================================================
766 DNSServiceQueryRecord(
767 DNSServiceRef
* outRef
,
768 DNSServiceFlags inFlags
,
769 uint32_t inInterfaceIndex
,
773 DNSServiceQueryRecordReply inCallBack
,
776 DNSServiceErrorType err
;
778 #if( DNS_SD_CLIENT_ENABLED )
779 if( gDNSSDServerCompatible
)
781 err
= DNSServiceQueryRecord_client( outRef
, gDNSSDServer
, inFlags
, inInterfaceIndex
, inName
, inRRType
, inRRClass
,
782 inCallBack
, inContext
);
787 #if( DNS_SD_DIRECT_ENABLED )
788 err
= DNSServiceQueryRecord_direct( outRef
, inFlags
, inInterfaceIndex
, inName
, inRRType
, inRRClass
,
789 inCallBack
, inContext
);
792 DEBUG_UNUSED( outRef
);
793 DEBUG_UNUSED( inFlags
);
794 DEBUG_UNUSED( inName
);
795 DEBUG_UNUSED( inInterfaceIndex
);
796 DEBUG_UNUSED( inName
);
797 DEBUG_UNUSED( inRRType
);
798 DEBUG_UNUSED( inRRClass
);
799 DEBUG_UNUSED( inCallBack
);
800 DEBUG_UNUSED( inContext
);
802 err
= kUnsupportedErr
;
810 //===========================================================================================================================
811 // DNSServiceReconfirmRecord
812 //===========================================================================================================================
815 DNSServiceReconfirmRecord(
816 DNSServiceFlags inFlags
,
817 uint32_t inInterfaceIndex
,
821 uint16_t inRDataSize
,
822 const void * inRData
)
824 #if( DNS_SD_CLIENT_ENABLED )
825 if( gDNSSDServerCompatible
)
827 DNSServiceReconfirmRecord_client( gDNSSDServer
, inFlags
, inInterfaceIndex
, inName
, inRRType
, inRRClass
,
828 inRDataSize
, inRData
);
833 #if( DNS_SD_DIRECT_ENABLED )
834 DNSServiceReconfirmRecord_direct( inFlags
, inInterfaceIndex
, inName
, inRRType
, inRRClass
, inRDataSize
, inRData
);
837 DEBUG_UNUSED( inFlags
);
838 DEBUG_UNUSED( inInterfaceIndex
);
839 DEBUG_UNUSED( inName
);
840 DEBUG_UNUSED( inRRType
);
841 DEBUG_UNUSED( inRRClass
);
842 DEBUG_UNUSED( inRDataSize
);
843 DEBUG_UNUSED( inRData
);
854 #pragma mark == Utilities ==
857 //===========================================================================================================================
860 // Copied from dnssd_clientstub.c.
861 //===========================================================================================================================
863 DEBUG_LOCAL
int DomainEndsInDot( const char *dom
)
867 while(*dom
&& *(dom
+ 1))
869 if (*dom
== '\\') // advance past escaped byte sequence
871 if (*(dom
+ 1) >= '0' && *(dom
+ 1) <= '9') dom
+= 4;
874 else dom
++; // else read one character
876 return (*dom
== '.');
881 #pragma mark == TXT Record Building ==
884 //===========================================================================================================================
886 //===========================================================================================================================
888 typedef struct _TXTRecordRef_t _TXTRecordRef_t
;
889 struct _TXTRecordRef_t
895 //===========================================================================================================================
897 //===========================================================================================================================
899 DEBUG_LOCAL DNSServiceErrorType
900 TXTRecordGetValuePtrInternal(
902 const void * inTXTBytes
,
905 uint16_t * outItemSize
,
906 const void ** outValue
,
907 uint8_t * outValueSize
);
909 DEBUG_LOCAL DNSServiceErrorType
910 TXTRecordGetItemAtIndexInternal(
912 const void * inTXTBytes
,
915 uint16_t * outItemSize
,
917 const void ** outValue
,
918 uint8_t * outValueSize
);
920 DEBUG_LOCAL
int TXTRecordMemEqv( const void *inLeft
, size_t inLeftSize
, const void *inRight
, size_t inRightSize
);
922 //===========================================================================================================================
924 //===========================================================================================================================
926 DNSServiceErrorType
TXTRecordCreate( TXTRecordRef
*outRef
)
928 DNSServiceErrorType err
;
931 require_action_expect( outRef
, exit
, err
= kDNSServiceErr_BadParam
);
933 obj
= (TXTRecordRef
) calloc( 1, sizeof( *obj
) );
934 require_action( obj
, exit
, err
= kDNSServiceErr_NoMemory
);
937 err
= kDNSServiceErr_NoError
;
943 //===========================================================================================================================
944 // TXTRecordDeallocate
945 //===========================================================================================================================
947 void TXTRecordDeallocate( TXTRecordRef inRef
)
952 if( inRef
->txt
) free( inRef
->txt
);
957 //===========================================================================================================================
959 //===========================================================================================================================
961 DNSServiceErrorType
TXTRecordSetValue( TXTRecordRef inRef
, const char *inKey
, uint8_t inValueSize
, const void *inValue
)
963 DNSServiceErrorType err
;
968 uintptr_t itemOffset
;
969 uint16_t oldItemSize
;
970 uint16_t newItemSize
;
974 require_action_expect( inRef
, exit
, err
= kDNSServiceErr_BadParam
);
975 require_action_expect( inKey
, exit
, err
= kDNSServiceErr_BadParam
);
976 require_action_expect( inValue
|| ( inValueSize
== 0 ), exit
, err
= kDNSServiceErr_BadParam
);
978 // Make sure the key is printable US-ASCII values (0x20-0x7E), excluding '=' (0x3D).
980 for( p
= inKey
; *p
!= '\0'; ++p
)
982 if( ( *p
< 0x20 ) || ( *p
> 0x7E ) || ( *p
== 0x3D ) )
987 keySize
= (size_t)( p
- inKey
);
988 require_action( ( keySize
> 0 ) && ( keySize
<= 255 ) && ( *p
== '\0' ), exit
, err
= kDNSServiceErr_Invalid
);
990 // Make sure the total item size does not exceed 255 bytes.
992 newItemSize
= (uint16_t) keySize
;
993 if( inValue
) newItemSize
+= 1; // Add '=' (only if there is a non-NULL value)
994 newItemSize
= (uint16_t)( newItemSize
+ inValueSize
);
995 require_action( newItemSize
<= 255, exit
, err
= kDNSServiceErr_Invalid
);
997 // Search for an existing item with the same key. If found, replace its value. Otherwise, append a new item.
999 err
= TXTRecordGetValuePtrInternal( inRef
->size
, inRef
->txt
, inKey
, &item
, &oldItemSize
, NULL
, NULL
);
1000 if( err
== kDNSServiceErr_NoError
)
1002 if( newItemSize
> oldItemSize
)
1004 // Expand the buffer then shift subsequent item(s) forward to make room for the larger value.
1005 // Note: this saves off and restores the item pointer since the pointer is invalidated by realloc.
1007 itemOffset
= (uintptr_t)( item
- inRef
->txt
);
1008 delta
= (uint16_t)( newItemSize
- oldItemSize
);
1009 txt
= (uint8_t *) realloc( inRef
->txt
, (size_t)( inRef
->size
+ delta
) );
1010 require_action( txt
, exit
, err
= kDNSServiceErr_NoMemory
);
1012 item
= txt
+ itemOffset
;
1013 itemEnd
= item
+ ( 1 + oldItemSize
);
1014 memmove( item
+ ( 1 + newItemSize
), itemEnd
, (size_t)( ( inRef
->txt
+ inRef
->size
) - itemEnd
) );
1016 inRef
->size
= (uint16_t)( inRef
->size
+ delta
);
1018 else if( newItemSize
< oldItemSize
)
1020 // Shift subsequent item(s) backward to take up the slack then shrink the buffer to fit.
1021 // Note: this saves off and restores the item pointer since the pointer is invalidated by realloc.
1023 itemEnd
= item
+ ( 1 + oldItemSize
);
1024 memmove( item
+ ( 1 + newItemSize
), itemEnd
, (size_t)( ( inRef
->txt
+ inRef
->size
) - itemEnd
) );
1026 itemOffset
= (uintptr_t)( item
- inRef
->txt
);
1027 inRef
->size
-= ( oldItemSize
- newItemSize
);
1028 txt
= (uint8_t *) realloc( inRef
->txt
, inRef
->size
);
1029 require_action( txt
, exit
, err
= kDNSServiceErr_NoMemory
);
1031 item
= txt
+ itemOffset
;
1037 // Resize the buffer to hold the new item.
1039 delta
= (uint16_t)( 1 + newItemSize
);
1040 txt
= (uint8_t *) realloc( inRef
->txt
, (size_t)( inRef
->size
+ delta
) );
1041 require_action( txt
, exit
, err
= kDNSServiceErr_NoMemory
);
1043 item
= txt
+ inRef
->size
;
1045 inRef
->size
= (uint16_t)( inRef
->size
+ delta
);
1048 // Write the new key/value pair to the TXT record in the form key[=<value>].
1049 // Note: This always writes the entire item to handle case changes in the key.
1051 *item
++ = (uint8_t) newItemSize
;
1052 memcpy( item
, inKey
, keySize
);
1054 if( inValue
) *item
++ = '='; // Add '=' (only if there is a non-NULL value)
1055 memcpy( item
, inValue
, inValueSize
);
1056 err
= kDNSServiceErr_NoError
;
1062 //===========================================================================================================================
1063 // TXTRecordRemoveValue
1064 //===========================================================================================================================
1066 DNSServiceErrorType
TXTRecordRemoveValue( TXTRecordRef inRef
, const char *inKey
)
1068 DNSServiceErrorType err
;
1075 err
= TXTRecordGetValuePtrInternal( inRef
->size
, inRef
->txt
, inKey
, &item
, &size
, NULL
, NULL
);
1076 require_noerr_quiet( err
, exit
);
1078 // Shift subsequent item(s) back to take up the slack of removing the item.
1080 itemEnd
= item
+ ( 1 + size
);
1081 txtEnd
= inRef
->txt
+ inRef
->size
;
1082 if( itemEnd
< txtEnd
)
1084 memmove( item
, itemEnd
, (size_t)( txtEnd
- itemEnd
) );
1087 // Shrink the buffer to fit. If size goes to 0, use free because realloc with size 0 is not consistent across platforms.
1089 inRef
->size
= (uint16_t)( inRef
->size
- ( (uint16_t)( itemEnd
- item
) ) );
1090 if( inRef
->size
> 0 )
1092 txt
= (uint8_t *) realloc( inRef
->txt
, inRef
->size
);
1093 require_action_quiet( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1106 //===========================================================================================================================
1107 // TXTRecordGetLength
1108 //===========================================================================================================================
1110 uint16_t TXTRecordGetLength( TXTRecordRef inRef
)
1114 if( inRef
&& inRef
->txt
)
1116 return( inRef
->size
);
1121 //===========================================================================================================================
1122 // TXTRecordGetBytesPtr
1123 //===========================================================================================================================
1125 const void * TXTRecordGetBytesPtr( TXTRecordRef inRef
)
1129 if( inRef
&& inRef
->txt
)
1131 return( inRef
->txt
);
1138 #pragma mark == TXT Record Parsing ==
1141 //===========================================================================================================================
1142 // TXTRecordGetValuePtr
1143 //===========================================================================================================================
1146 TXTRecordGetValuePtr(
1148 const void * inTXTBytes
,
1150 const void ** outValue
,
1151 uint8_t * outValueSize
)
1153 return( TXTRecordGetValuePtrInternal( inTXTSize
, inTXTBytes
, inKey
, NULL
, NULL
, outValue
, outValueSize
) );
1156 //===========================================================================================================================
1157 // TXTRecordGetCount
1158 //===========================================================================================================================
1160 uint16_t TXTRecordGetCount( uint16_t inTXTSize
, const void *inTXTBytes
)
1166 require_action( inTXTBytes
, exit
, n
= 0 );
1169 p
= (const uint8_t *) inTXTBytes
;
1175 require_action( p
<= q
, exit
, n
= 0 );
1182 //===========================================================================================================================
1183 // TXTRecordGetItemAtIndex
1184 //===========================================================================================================================
1187 TXTRecordGetItemAtIndex(
1189 const void * inTXTBytes
,
1192 const void ** outValue
,
1193 uint8_t * outValueSize
)
1195 return( TXTRecordGetItemAtIndexInternal( inTXTSize
, inTXTBytes
, inIndex
, NULL
, NULL
, inKeyBuffer
, outValue
, outValueSize
) );
1200 #pragma mark == TXT Record Internal ==
1203 //===========================================================================================================================
1204 // TXTRecordGetValuePtrInternal
1205 //===========================================================================================================================
1207 DEBUG_LOCAL DNSServiceErrorType
1208 TXTRecordGetValuePtrInternal(
1210 const void * inTXTBytes
,
1213 uint16_t * outItemSize
,
1214 const void ** outValue
,
1215 uint8_t * outValueSize
)
1217 DNSServiceErrorType err
;
1222 const uint8_t * key
;
1223 const uint8_t * keyEnd
;
1224 const uint8_t * value
;
1225 const uint8_t * valueEnd
;
1227 require_action_quiet( inTXTBytes
, exit
, err
= kDNSServiceErr_NoSuchKey
);
1228 require_action_expect( inKey
, exit
, err
= kDNSServiceErr_BadParam
);
1229 keySize
= strlen( inKey
);
1231 // The following initializations are not necessary, but some compilers warn because they cannot detect it.
1237 // Find the item with the specified key.
1239 p
= (const uint8_t *) inTXTBytes
;
1243 // Parse the key/value tokens. No '=' means the key takes up the entire item.
1246 require_action( r
<= q
, exit
, err
= kDNSServiceErr_Invalid
);
1249 keyEnd
= (const uint8_t *) memchr( key
, '=', *p
);
1260 if( TXTRecordMemEqv( key
, (size_t)( keyEnd
- key
), inKey
, keySize
) == 0 )
1268 require_action_quiet( p
< q
, exit
, err
= kDNSServiceErr_NoSuchKey
);
1270 // Fill in the results the caller wants.
1272 if( outItem
) *outItem
= (uint8_t *) p
;
1273 if( outItemSize
) *outItemSize
= *p
;
1274 if( outValue
) *outValue
= ( value
== keyEnd
) ? NULL
: value
; // NULL value ptr means no value.
1275 if( outValueSize
) *outValueSize
= (uint8_t)( valueEnd
- value
);
1276 err
= kDNSServiceErr_NoError
;
1282 //===========================================================================================================================
1283 // TXTRecordGetItemAtIndexInternal
1284 //===========================================================================================================================
1286 DEBUG_LOCAL DNSServiceErrorType
1287 TXTRecordGetItemAtIndexInternal(
1289 const void * inTXTBytes
,
1292 uint16_t * outItemSize
,
1294 const void ** outValue
,
1295 uint8_t * outValueSize
)
1297 DNSServiceErrorType err
;
1302 const uint8_t * key
;
1303 const uint8_t * keyEnd
;
1304 const uint8_t * value
;
1305 const uint8_t * valueEnd
;
1307 require_action_quiet( inTXTBytes
, exit
, err
= kDNSServiceErr_Invalid
);
1309 // Find the Nth item in the TXT record.
1312 p
= (const uint8_t *) inTXTBytes
;
1316 if( n
== inIndex
) break;
1320 require_action( p
<= q
, exit
, err
= kDNSServiceErr_Invalid
);
1322 require_action_quiet( p
< q
, exit
, err
= kDNSServiceErr_Invalid
);
1324 // Item found. Parse the key/value tokens. No '=' means the key takes up the entire item.
1327 require_action( r
<= q
, exit
, err
= kDNSServiceErr_Invalid
);
1330 keyEnd
= (const uint8_t *) memchr( key
, '=', *p
);
1342 // Fill in the results the caller wants.
1344 if( outItem
) *outItem
= (uint8_t *) p
;
1345 if( outItemSize
) *outItemSize
= *p
;
1348 n
= (uint16_t)( keyEnd
- key
);
1349 memcpy( inKeyBuffer
, key
, n
);
1350 inKeyBuffer
[ n
] = '\0';
1352 if( outValue
) *outValue
= ( value
== keyEnd
) ? NULL
: value
; // NULL value ptr means no value.
1353 if( outValueSize
) *outValueSize
= (uint8_t)( valueEnd
- value
);
1354 err
= kDNSServiceErr_NoError
;
1360 //===========================================================================================================================
1362 //===========================================================================================================================
1364 DEBUG_LOCAL
int TXTRecordMemEqv( const void *inLeft
, size_t inLeftSize
, const void *inRight
, size_t inRightSize
)
1368 const uint8_t * end
;
1372 if( inLeftSize
< inRightSize
) return( -1 );
1373 if( inLeftSize
> inRightSize
) return( 1 );
1375 p1
= (const uint8_t *) inLeft
;
1376 p2
= (const uint8_t *) inRight
;
1377 end
= p1
+ inLeftSize
;
1380 c1
= tolower( *p1
);
1381 c2
= tolower( *p2
);
1382 if( c1
< c2
) return( -1 );
1383 if( c1
> c2
) return( 1 );
1392 //===========================================================================================================================
1394 //===========================================================================================================================
1396 DNSServiceErrorType
TXTRecordTest( void );
1398 DNSServiceErrorType
TXTRecordTest( void )
1400 DNSServiceErrorType err
;
1410 // Create Existing Test
1412 s
= "\014Anon Allowed"
1414 "\025InstalledPlugins=JPEG";
1415 size
= (uint16_t) strlen( s
);
1417 n
= TXTRecordGetCount( size
, s
);
1418 require_action( n
== 3, exit
, err
= kDNSServiceErr_Unknown
);
1420 err
= TXTRecordGetValuePtr( size
, s
, "test", NULL
, NULL
);
1421 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1423 err
= TXTRecordGetValuePtr( size
, s
, "Anon", NULL
, NULL
);
1424 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1426 err
= TXTRecordGetValuePtr( size
, s
, "Allowed", NULL
, NULL
);
1427 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1429 err
= TXTRecordGetValuePtr( size
, s
, "", NULL
, NULL
);
1430 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1432 err
= TXTRecordGetValuePtr( size
, s
, "Anon Allowed", &value
, &valueSize
);
1433 require_noerr( err
, exit
);
1434 require_action( value
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1435 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1437 err
= TXTRecordGetValuePtr( size
, s
, "Options", &value
, &valueSize
);
1438 require_noerr( err
, exit
);
1439 require_action( value
!= NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1440 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1442 err
= TXTRecordGetValuePtr( size
, s
, "InstalledPlugins", &value
, &valueSize
);
1443 require_noerr( err
, exit
);
1444 require_action( valueSize
== 4, exit
, err
= kDNSServiceErr_Unknown
);
1445 require_action( memcmp( value
, "JPEG", 4 ) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1448 err
= TXTRecordGetItemAtIndex( size
, s
, 0, key
, &value
, &valueSize
);
1449 require_noerr( err
, exit
);
1450 require_action( strcmp( key
, "Anon Allowed" ) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1451 require_action( value
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1452 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1455 err
= TXTRecordGetItemAtIndex( size
, s
, 1, key
, &value
, &valueSize
);
1456 require_noerr( err
, exit
);
1457 require_action( strcmp( key
, "Options" ) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1458 require_action( value
!= NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1459 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1462 err
= TXTRecordGetItemAtIndex( size
, s
, 2, key
, &value
, &valueSize
);
1463 require_noerr( err
, exit
);
1464 require_action( strcmp( key
, "InstalledPlugins" ) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1465 require_action( value
!= NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1466 require_action( valueSize
== 4, exit
, err
= kDNSServiceErr_Unknown
);
1467 require_action( memcmp( value
, "JPEG", valueSize
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1470 err
= TXTRecordGetItemAtIndex( size
, s
, 3, key
, &value
, &valueSize
);
1471 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1475 err
= TXTRecordCreate( &ref
);
1476 require_noerr( err
, exit
);
1478 txt
= TXTRecordGetBytesPtr( ref
);
1479 require_action( txt
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1480 size
= TXTRecordGetLength( ref
);
1481 require_action( size
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1483 TXTRecordDeallocate( ref
);
1485 // Create Single Test
1487 err
= TXTRecordCreate( &ref
);
1488 require_noerr( err
, exit
);
1490 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1491 require_noerr( err
, exit
);
1493 txt
= TXTRecordGetBytesPtr( ref
);
1494 require_action( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1495 size
= TXTRecordGetLength( ref
);
1496 require_action( size
== 13, exit
, err
= kDNSServiceErr_Unknown
);
1497 require_action( memcmp( txt
, "\014Anon Allowed", size
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1499 n
= TXTRecordGetCount( size
, txt
);
1500 require_action( n
== 1, exit
, err
= kDNSServiceErr_Unknown
);
1502 err
= TXTRecordGetValuePtr( size
, txt
, "test", NULL
, NULL
);
1503 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1505 err
= TXTRecordGetValuePtr( size
, txt
, "Anon", NULL
, NULL
);
1506 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1508 err
= TXTRecordGetValuePtr( size
, txt
, "Allowed", NULL
, NULL
);
1509 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1511 err
= TXTRecordGetValuePtr( size
, txt
, "", NULL
, NULL
);
1512 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1514 err
= TXTRecordGetValuePtr( size
, txt
, "Anon Allowed", &value
, &valueSize
);
1515 require_noerr( err
, exit
);
1516 require_action( value
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1517 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1519 err
= TXTRecordGetValuePtr( size
, txt
, "aNoN aLlOwEd", &value
, &valueSize
);
1520 require_noerr( err
, exit
);
1521 require_action( value
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1522 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1524 TXTRecordDeallocate( ref
);
1526 // Create Multiple Test
1528 err
= TXTRecordCreate( &ref
);
1529 require_noerr( err
, exit
);
1531 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1532 require_noerr( err
, exit
);
1534 err
= TXTRecordSetValue( ref
, "Options", 0, "" );
1535 require_noerr( err
, exit
);
1537 err
= TXTRecordSetValue( ref
, "InstalledPlugins", 4, "JPEG" );
1538 require_noerr( err
, exit
);
1540 txt
= TXTRecordGetBytesPtr( ref
);
1541 require_action( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1542 size
= TXTRecordGetLength( ref
);
1543 require_action( size
== 44, exit
, err
= kDNSServiceErr_Unknown
);
1544 require_action( memcmp( txt
,
1547 "\025InstalledPlugins=JPEG",
1548 size
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1550 n
= TXTRecordGetCount( size
, txt
);
1551 require_action( n
== 3, exit
, err
= kDNSServiceErr_Unknown
);
1553 err
= TXTRecordGetValuePtr( size
, txt
, "test", NULL
, NULL
);
1554 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1556 err
= TXTRecordGetValuePtr( size
, txt
, "Anon", NULL
, NULL
);
1557 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1559 err
= TXTRecordGetValuePtr( size
, txt
, "Allowed", NULL
, NULL
);
1560 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1562 err
= TXTRecordGetValuePtr( size
, txt
, "", NULL
, NULL
);
1563 require_action( err
!= kDNSServiceErr_NoError
, exit
, err
= kDNSServiceErr_Unknown
);
1565 err
= TXTRecordGetValuePtr( size
, txt
, "Anon Allowed", &value
, &valueSize
);
1566 require_noerr( err
, exit
);
1567 require_action( value
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1568 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1570 err
= TXTRecordGetValuePtr( size
, txt
, "Options", &value
, &valueSize
);
1571 require_noerr( err
, exit
);
1572 require_action( value
!= NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1573 require_action( valueSize
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1575 err
= TXTRecordGetValuePtr( size
, txt
, "InstalledPlugins", &value
, &valueSize
);
1576 require_noerr( err
, exit
);
1577 require_action( valueSize
== 4, exit
, err
= kDNSServiceErr_Unknown
);
1578 require_action( memcmp( value
, "JPEG", 4 ) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1580 TXTRecordDeallocate( ref
);
1582 // Remove Single Test
1584 err
= TXTRecordCreate( &ref
);
1585 require_noerr( err
, exit
);
1587 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1588 require_noerr( err
, exit
);
1590 err
= TXTRecordRemoveValue( ref
, "Anon Allowed" );
1591 require_noerr( err
, exit
);
1593 txt
= TXTRecordGetBytesPtr( ref
);
1594 require_action( txt
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1595 size
= TXTRecordGetLength( ref
);
1596 require_action( size
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1598 TXTRecordDeallocate( ref
);
1600 // Remove Multiple Test
1602 err
= TXTRecordCreate( &ref
);
1603 require_noerr( err
, exit
);
1605 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1606 require_noerr( err
, exit
);
1608 err
= TXTRecordSetValue( ref
, "Options", 0, "" );
1609 require_noerr( err
, exit
);
1611 err
= TXTRecordSetValue( ref
, "InstalledPlugins", 4, "JPEG" );
1612 require_noerr( err
, exit
);
1614 err
= TXTRecordRemoveValue( ref
, "Options" );
1615 require_noerr( err
, exit
);
1617 txt
= TXTRecordGetBytesPtr( ref
);
1618 require_action( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1619 size
= TXTRecordGetLength( ref
);
1620 require_action( size
== 35, exit
, err
= kDNSServiceErr_Unknown
);
1621 require_action( memcmp( txt
,
1623 "\025InstalledPlugins=JPEG",
1624 size
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1626 n
= TXTRecordGetCount( size
, txt
);
1627 require_action( n
== 2, exit
, err
= kDNSServiceErr_Unknown
);
1629 err
= TXTRecordRemoveValue( ref
, "Anon Allowed" );
1630 require_noerr( err
, exit
);
1632 txt
= TXTRecordGetBytesPtr( ref
);
1633 require_action( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1634 size
= TXTRecordGetLength( ref
);
1635 require_action( size
== 22, exit
, err
= kDNSServiceErr_Unknown
);
1636 require_action( memcmp( txt
,
1637 "\025InstalledPlugins=JPEG",
1638 size
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1640 n
= TXTRecordGetCount( size
, txt
);
1641 require_action( n
== 1, exit
, err
= kDNSServiceErr_Unknown
);
1643 err
= TXTRecordRemoveValue( ref
, "InstalledPlugins" );
1644 require_noerr( err
, exit
);
1646 txt
= TXTRecordGetBytesPtr( ref
);
1647 require_action( txt
== NULL
, exit
, err
= kDNSServiceErr_Unknown
);
1648 size
= TXTRecordGetLength( ref
);
1649 require_action( size
== 0, exit
, err
= kDNSServiceErr_Unknown
);
1651 TXTRecordDeallocate( ref
);
1655 err
= TXTRecordCreate( &ref
);
1656 require_noerr( err
, exit
);
1658 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1659 require_noerr( err
, exit
);
1661 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1662 require_noerr( err
, exit
);
1664 err
= TXTRecordSetValue( ref
, "Options", 0, "" );
1665 require_noerr( err
, exit
);
1667 err
= TXTRecordSetValue( ref
, "Options", 0, "" );
1668 require_noerr( err
, exit
);
1670 err
= TXTRecordSetValue( ref
, "InstalledPlugins", 4, "JPEG" );
1671 require_noerr( err
, exit
);
1673 err
= TXTRecordSetValue( ref
, "InstalledPlugins", 4, "JPEG" );
1674 require_noerr( err
, exit
);
1676 txt
= TXTRecordGetBytesPtr( ref
);
1677 require_action( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1678 size
= TXTRecordGetLength( ref
);
1679 require_action( size
== 44, exit
, err
= kDNSServiceErr_Unknown
);
1680 require_action( memcmp( txt
,
1683 "\025InstalledPlugins=JPEG",
1684 size
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1686 err
= TXTRecordSetValue( ref
, "Anon Allowed", 4, "test" );
1687 require_noerr( err
, exit
);
1689 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, "" );
1690 require_noerr( err
, exit
);
1692 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, NULL
);
1693 require_noerr( err
, exit
);
1695 err
= TXTRecordSetValue( ref
, "Anon Allowed", 0, "" );
1696 require_noerr( err
, exit
);
1698 err
= TXTRecordSetValue( ref
, "Anon Allowed", 4, "test" );
1699 require_noerr( err
, exit
);
1701 txt
= TXTRecordGetBytesPtr( ref
);
1702 require_action( txt
, exit
, err
= kDNSServiceErr_Unknown
);
1703 size
= TXTRecordGetLength( ref
);
1704 require_action( size
== 49, exit
, err
= kDNSServiceErr_Unknown
);
1705 require_action( memcmp( txt
,
1706 "\021Anon Allowed=test"
1708 "\025InstalledPlugins=JPEG",
1709 size
) == 0, exit
, err
= kDNSServiceErr_Unknown
);
1711 TXTRecordDeallocate( ref
);