]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/DNSSD.c
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / DNSSD.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: DNSSD.c,v $
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.
31
32 Revision 1.2 2004/05/03 10:34:24 bradley
33 Implemented preliminary version of the TXTRecord API.
34
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.
38
39 */
40
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45
46 #include "CommonServices.h"
47 #include "DebugServices.h"
48
49 #include "DNSSDDirect.h"
50 #include "RMxClient.h"
51
52 #include "DNSSD.h"
53
54 #ifdef __cplusplus
55 extern "C" {
56 #endif
57
58 //===========================================================================================================================
59 // Constants
60 //===========================================================================================================================
61
62 #define DEBUG_NAME "[DNS-SD] "
63
64 //===========================================================================================================================
65 // Prototypes
66 //===========================================================================================================================
67
68 DEBUG_LOCAL int DomainEndsInDot( const char *dom );
69
70 //===========================================================================================================================
71 // Globals
72 //===========================================================================================================================
73
74 #if( DNS_SD_CLIENT_ENABLED )
75 const char * gDNSSDServer = NULL;
76 DEBUG_LOCAL bool gDNSSDServerCompatible = false;
77 #endif
78
79 #if 0
80 #pragma mark == General ==
81 #endif
82
83 //===========================================================================================================================
84 // DNSServiceInitialize
85 //===========================================================================================================================
86
87 DNSServiceErrorType DNSServiceInitialize( DNSServiceInitializeFlags inFlags, int inCacheEntryCount )
88 {
89 DNSServiceErrorType err;
90
91 #if( DNS_SD_CLIENT_ENABLED )
92 err = RMxClientInitialize();
93 if( err == kNoErr )
94 {
95 // Perform a version check to see if the server is compatible.
96
97 if( !( inFlags & kDNSServiceInitializeFlagsNoServerCheck ) )
98 {
99 err = DNSServiceCheckVersion();
100 if( err == kNoErr )
101 {
102 goto exit;
103 }
104 }
105 else
106 {
107 // Version check disabled so just assume the server is compatible.
108
109 gDNSSDServerCompatible = true;
110 goto exit;
111 }
112 }
113 #endif
114
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" );
118 #endif
119 err = DNSServiceInitialize_direct( inFlags, inCacheEntryCount );
120 goto exit;
121 #else
122 DEBUG_UNUSED( inFlags );
123 DEBUG_UNUSED( inCacheEntryCount );
124
125 err = kUnsupportedErr;
126 goto exit;
127 #endif
128
129 exit:
130 return( err );
131 }
132
133 //===========================================================================================================================
134 // DNSServiceFinalize
135 //===========================================================================================================================
136
137 void DNSServiceFinalize( void )
138 {
139 #if( DNS_SD_CLIENT_ENABLED )
140 RMxClientFinalize();
141 #endif
142
143 #if( DNS_SD_DIRECT_ENABLED )
144 DNSServiceFinalize_direct();
145 #endif
146 }
147
148 //===========================================================================================================================
149 // DNSServiceCheckVersion
150 //===========================================================================================================================
151
152 DNSServiceErrorType DNSServiceCheckVersion( void )
153 {
154 DNSServiceErrorType err;
155
156 #if( DNS_SD_CLIENT_ENABLED )
157 err = DNSServiceCheckVersion_client( gDNSSDServer );
158 if( err == kNoErr )
159 {
160 gDNSSDServerCompatible = true;
161 }
162 #else
163 err = kUnsupportedErr;
164 #endif
165
166 return( err );
167 }
168
169 #if 0
170 #pragma mark -
171 #pragma mark == Properties ==
172 #endif
173
174 //===========================================================================================================================
175 // DNSServiceCopyProperty
176 //===========================================================================================================================
177
178 DNSServiceErrorType DNSServiceCopyProperty( DNSPropertyCode inCode, DNSPropertyData *outData )
179 {
180 DNSServiceErrorType err;
181
182 #if( DNS_SD_CLIENT_ENABLED )
183 if( gDNSSDServerCompatible )
184 {
185 err = DNSServiceCopyProperty_client( gDNSSDServer, inCode, outData );
186 goto exit;
187 }
188 #else
189 DEBUG_UNUSED( inCode );
190 DEBUG_UNUSED( outData );
191 #endif
192
193 #if( DNS_SD_DIRECT_ENABLED )
194 err = kUnsupportedErr;
195 goto exit;
196 #else
197 err = kUnsupportedErr;
198 goto exit;
199 #endif
200
201 exit:
202 return( err );
203 }
204
205 //===========================================================================================================================
206 // DNSServiceReleaseProperty
207 //===========================================================================================================================
208
209 DNSServiceErrorType DNSServiceReleaseProperty( DNSPropertyData *inData )
210 {
211 DNSServiceErrorType err;
212
213 #if( DNS_SD_CLIENT_ENABLED )
214 if( gDNSSDServerCompatible )
215 {
216 err = DNSServiceReleaseProperty_client( inData );
217 goto exit;
218 }
219 #else
220 DEBUG_UNUSED( inData );
221 #endif
222
223 #if( DNS_SD_DIRECT_ENABLED )
224 err = kUnsupportedErr;
225 goto exit;
226 #else
227 err = kUnsupportedErr;
228 goto exit;
229 #endif
230
231 exit:
232 return( err );
233 }
234
235 #if 0
236 #pragma mark -
237 #pragma mark == Unix Domain Socket Access ==
238 #endif
239
240 //===========================================================================================================================
241 // DNSServiceRefSockFD
242 //===========================================================================================================================
243
244 int DNSServiceRefSockFD( DNSServiceRef inRef )
245 {
246 DEBUG_UNUSED( inRef );
247
248 dlog( kDebugLevelError, "DNSServiceRefSockFD is not supported\n" );
249 return( -1 );
250 }
251
252 //===========================================================================================================================
253 // DNSServiceProcessResult
254 //===========================================================================================================================
255
256 DNSServiceErrorType DNSServiceProcessResult( DNSServiceRef inRef )
257 {
258 DEBUG_UNUSED( inRef );
259
260 dlog( kDebugLevelError, "DNSServiceProcessResult is not supported\n" );
261 return( kDNSServiceErr_Unsupported );
262 }
263
264 //===========================================================================================================================
265 // DNSServiceRefDeallocate
266 //===========================================================================================================================
267
268 void DNSServiceRefDeallocate( DNSServiceRef inRef )
269 {
270 #if( DNS_SD_CLIENT_ENABLED )
271 if( gDNSSDServerCompatible )
272 {
273 DNSServiceRefDeallocate_client( inRef );
274 goto exit;
275 }
276 #endif
277
278 #if( DNS_SD_DIRECT_ENABLED )
279 DNSServiceRefDeallocate_direct( inRef );
280 goto exit;
281 #else
282 DEBUG_UNUSED( inRef );
283
284 goto exit;
285 #endif
286
287 exit:
288 return;
289 }
290
291 #if 0
292 #pragma mark -
293 #pragma mark == Domain Enumeration ==
294 #endif
295
296 //===========================================================================================================================
297 // DNSServiceEnumerateDomains
298 //===========================================================================================================================
299
300 DNSServiceErrorType
301 DNSServiceEnumerateDomains(
302 DNSServiceRef * outRef,
303 const DNSServiceFlags inFlags,
304 const uint32_t inInterfaceIndex,
305 const DNSServiceDomainEnumReply inCallBack,
306 void * inContext )
307 {
308 DNSServiceErrorType err;
309
310 #if( DNS_SD_CLIENT_ENABLED )
311 if( gDNSSDServerCompatible )
312 {
313 err = DNSServiceEnumerateDomains_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inCallBack, inContext );
314 goto exit;
315 }
316 #endif
317
318 #if( DNS_SD_DIRECT_ENABLED )
319 err = DNSServiceEnumerateDomains_direct( outRef, inFlags, inInterfaceIndex, inCallBack, inContext );
320 goto exit;
321 #else
322 DEBUG_UNUSED( outRef );
323 DEBUG_UNUSED( inFlags );
324 DEBUG_UNUSED( inInterfaceIndex );
325 DEBUG_UNUSED( inCallBack );
326 DEBUG_UNUSED( inContext );
327
328 err = kUnsupportedErr;
329 goto exit;
330 #endif
331
332 exit:
333 return( err );
334 }
335
336 #if 0
337 #pragma mark -
338 #pragma mark == Service Registration ==
339 #endif
340
341 //===========================================================================================================================
342 // DNSServiceRegister
343 //===========================================================================================================================
344
345 DNSServiceErrorType
346 DNSServiceRegister(
347 DNSServiceRef * outRef,
348 DNSServiceFlags inFlags,
349 uint32_t inInterfaceIndex,
350 const char * inName,
351 const char * inType,
352 const char * inDomain,
353 const char * inHost,
354 uint16_t inPort,
355 uint16_t inTXTSize,
356 const void * inTXT,
357 DNSServiceRegisterReply inCallBack,
358 void * inContext )
359 {
360 DNSServiceErrorType err;
361
362 #if( DNS_SD_CLIENT_ENABLED )
363 if( gDNSSDServerCompatible )
364 {
365 err = DNSServiceRegister_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inName, inType, inDomain,
366 inHost, inPort, inTXTSize, inTXT, inCallBack, inContext );
367 goto exit;
368 }
369 #endif
370
371 #if( DNS_SD_DIRECT_ENABLED )
372 err = DNSServiceRegister_direct( outRef, inFlags, inInterfaceIndex, inName, inType, inDomain, inHost, inPort,
373 inTXTSize, inTXT, inCallBack, inContext );
374 goto exit;
375 #else
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 );
388
389 err = kUnsupportedErr;
390 goto exit;
391 #endif
392
393 exit:
394 return( err );
395 }
396
397 //===========================================================================================================================
398 // DNSServiceAddRecord
399 //===========================================================================================================================
400
401 DNSServiceErrorType
402 DNSServiceAddRecord(
403 DNSServiceRef inRef,
404 DNSRecordRef * outRecordRef,
405 DNSServiceFlags inFlags,
406 uint16_t inRRType,
407 uint16_t inRDataSize,
408 const void * inRData,
409 uint32_t inTTL )
410 {
411 DNSServiceErrorType err;
412
413 #if( DNS_SD_CLIENT_ENABLED )
414 if( gDNSSDServerCompatible )
415 {
416 err = DNSServiceAddRecord_client( inRef, outRecordRef, inFlags, inRRType, inRDataSize, inRData, inTTL );
417 goto exit;
418 }
419 #endif
420
421 #if( DNS_SD_DIRECT_ENABLED )
422 err = DNSServiceAddRecord_direct( inRef, outRecordRef, inFlags, inRRType, inRDataSize, inRData, inTTL );
423 goto exit;
424 #else
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 );
432
433 err = kUnsupportedErr;
434 goto exit;
435 #endif
436
437 exit:
438 return( err );
439 }
440
441 //===========================================================================================================================
442 // DNSServiceUpdateRecord
443 //===========================================================================================================================
444
445 DNSServiceErrorType
446 DNSServiceUpdateRecord(
447 DNSServiceRef inRef,
448 DNSRecordRef inRecordRef,
449 DNSServiceFlags inFlags,
450 uint16_t inRDataSize,
451 const void * inRData,
452 uint32_t inTTL )
453 {
454 DNSServiceErrorType err;
455
456 #if( DNS_SD_CLIENT_ENABLED )
457 if( gDNSSDServerCompatible )
458 {
459 err = DNSServiceUpdateRecord_client( inRef, inRecordRef, inFlags, inRDataSize, inRData, inTTL );
460 goto exit;
461 }
462 #endif
463
464 #if( DNS_SD_DIRECT_ENABLED )
465 err = DNSServiceUpdateRecord_direct( inRef, inRecordRef, inFlags, inRDataSize, inRData, inTTL );
466 goto exit;
467 #else
468 DEBUG_UNUSED( inRef );
469 DEBUG_UNUSED( inRecordRef );
470 DEBUG_UNUSED( inFlags );
471 DEBUG_UNUSED( inRDataSize );
472 DEBUG_UNUSED( inRData );
473 DEBUG_UNUSED( inTTL );
474
475 err = kUnsupportedErr;
476 goto exit;
477 #endif
478
479 exit:
480 return( err );
481 }
482
483 //===========================================================================================================================
484 // DNSServiceRemoveRecord
485 //===========================================================================================================================
486
487 DNSServiceErrorType DNSServiceRemoveRecord( DNSServiceRef inRef, DNSRecordRef inRecordRef, DNSServiceFlags inFlags )
488 {
489 DNSServiceErrorType err;
490
491 #if( DNS_SD_CLIENT_ENABLED )
492 if( gDNSSDServerCompatible )
493 {
494 err = DNSServiceRemoveRecord_client( inRef, inRecordRef, inFlags );
495 goto exit;
496 }
497 #endif
498
499 #if( DNS_SD_DIRECT_ENABLED )
500 err = DNSServiceRemoveRecord_direct( inRef, inRecordRef, inFlags );
501 goto exit;
502 #else
503 DEBUG_UNUSED( inRef );
504 DEBUG_UNUSED( inRecordRef );
505 DEBUG_UNUSED( inFlags );
506
507 err = kUnsupportedErr;
508 goto exit;
509 #endif
510
511 exit:
512 return( err );
513 }
514
515 #if 0
516 #pragma mark -
517 #pragma mark == Service Discovery ==
518 #endif
519
520 //===========================================================================================================================
521 // DNSServiceBrowse
522 //===========================================================================================================================
523
524 DNSServiceErrorType
525 DNSServiceBrowse(
526 DNSServiceRef * outRef,
527 DNSServiceFlags inFlags,
528 uint32_t inInterfaceIndex,
529 const char * inType,
530 const char * inDomain,
531 DNSServiceBrowseReply inCallBack,
532 void * inContext )
533 {
534 DNSServiceErrorType err;
535
536 #if( DNS_SD_CLIENT_ENABLED )
537 if( gDNSSDServerCompatible )
538 {
539 err = DNSServiceBrowse_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inType, inDomain,
540 inCallBack, inContext );
541 goto exit;
542 }
543 #endif
544
545 #if( DNS_SD_DIRECT_ENABLED )
546 err = DNSServiceBrowse_direct( outRef, inFlags, inInterfaceIndex, inType, inDomain, inCallBack, inContext );
547 goto exit;
548 #else
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 );
556
557 err = kUnsupportedErr;
558 goto exit;
559 #endif
560
561 exit:
562 return( err );
563 }
564
565 //===========================================================================================================================
566 // DNSServiceResolve
567 //===========================================================================================================================
568
569 DNSServiceErrorType
570 DNSServiceResolve(
571 DNSServiceRef * outRef,
572 DNSServiceFlags inFlags,
573 uint32_t inInterfaceIndex,
574 const char * inName,
575 const char * inType,
576 const char * inDomain,
577 DNSServiceResolveReply inCallBack,
578 void * inContext )
579 {
580 DNSServiceErrorType err;
581
582 #if( DNS_SD_CLIENT_ENABLED )
583 if( gDNSSDServerCompatible )
584 {
585 err = DNSServiceResolve_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inName, inType, inDomain,
586 inCallBack, inContext );
587 goto exit;
588 }
589 #endif
590
591 #if( DNS_SD_DIRECT_ENABLED )
592 err = DNSServiceResolve_direct( outRef, inFlags, inInterfaceIndex, inName, inType, inDomain, inCallBack, inContext );
593 goto exit;
594 #else
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 );
603
604 err = kUnsupportedErr;
605 goto exit;
606 #endif
607
608 exit:
609 return( err );
610 }
611
612 #if 0
613 #pragma mark -
614 #pragma mark == Special Purpose ==
615 #endif
616
617 //===========================================================================================================================
618 // DNSServiceConstructFullName
619 //
620 // Copied from dnssd_clientstub.c with minimal changes to support NULL/empty name, type, and domain.
621 //===========================================================================================================================
622
623 int DNSServiceConstructFullName( char *fullName, const char *service, const char *regtype, const char *domain )
624 {
625 size_t len;
626 unsigned char c;
627 char *fn = fullName;
628 const char *s = service;
629 const char *r = regtype;
630 const char *d = domain;
631
632 if (service && *service)
633 {
634 while(*s)
635 {
636 c = (unsigned char) *s++;
637 if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
638 else if (c <= ' ') // escape non-printable characters
639 {
640 *fn++ = '\\';
641 *fn++ = (char) ('0' + (c / 100));
642 *fn++ = (char) ('0' + (c / 10) % 10);
643 c = (unsigned char)('0' + (c % 10));
644 }
645 *fn++ = (char) c;
646 }
647 *fn++ = '.';
648 }
649
650 if (regtype && *regtype)
651 {
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;
656 while(*r)
657 *fn++ = *r++;
658 if (!DomainEndsInDot(regtype)) *fn++ = '.';
659 }
660
661 if (!domain || !(*domain))
662 {
663 domain = "local.";
664 d = domain;
665 }
666 len = strlen(domain);
667 if (!len) return -1;
668 while(*d)
669 *fn++ = *d++;
670 if (!DomainEndsInDot(domain)) *fn++ = '.';
671 *fn = '\0';
672 return 0;
673 }
674
675 //===========================================================================================================================
676 // DNSServiceCreateConnection
677 //===========================================================================================================================
678
679 DNSServiceErrorType DNSServiceCreateConnection( DNSServiceRef *outRef )
680 {
681 DNSServiceErrorType err;
682
683 #if( DNS_SD_CLIENT_ENABLED )
684 if( gDNSSDServerCompatible )
685 {
686 err = DNSServiceCreateConnection_client( outRef, gDNSSDServer );
687 goto exit;
688 }
689 #endif
690
691 #if( DNS_SD_DIRECT_ENABLED )
692 err = DNSServiceCreateConnection_direct( outRef );
693 goto exit;
694 #else
695 DEBUG_UNUSED( outRef );
696
697 err = kUnsupportedErr;
698 goto exit;
699 #endif
700
701 exit:
702 return( err );
703 }
704
705 //===========================================================================================================================
706 // DNSServiceRegisterRecord
707 //===========================================================================================================================
708
709 DNSServiceErrorType
710 DNSServiceRegisterRecord(
711 DNSServiceRef inRef,
712 DNSRecordRef * outRecordRef,
713 DNSServiceFlags inFlags,
714 uint32_t inInterfaceIndex,
715 const char * inName,
716 uint16_t inRRType,
717 uint16_t inRRClass,
718 uint16_t inRDataSize,
719 const void * inRData,
720 uint32_t inTTL,
721 DNSServiceRegisterRecordReply inCallBack,
722 void * inContext )
723 {
724 DNSServiceErrorType err;
725
726 #if( DNS_SD_CLIENT_ENABLED )
727 if( gDNSSDServerCompatible )
728 {
729 err = DNSServiceRegisterRecord_client( inRef, outRecordRef, inFlags, inInterfaceIndex, inName,
730 inRRType, inRRClass, inRDataSize, inRData, inTTL, inCallBack, inContext );
731 goto exit;
732 }
733 #endif
734
735 #if( DNS_SD_DIRECT_ENABLED )
736 err = DNSServiceRegisterRecord_direct( inRef, outRecordRef, inFlags, inInterfaceIndex, inName,
737 inRRType, inRRClass, inRDataSize, inRData, inTTL, inCallBack, inContext );
738 goto exit;
739 #else
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 );
752
753 err = kUnsupportedErr;
754 goto exit;
755 #endif
756
757 exit:
758 return( err );
759 }
760
761 //===========================================================================================================================
762 // DNSServiceQueryRecord
763 //===========================================================================================================================
764
765 DNSServiceErrorType
766 DNSServiceQueryRecord(
767 DNSServiceRef * outRef,
768 DNSServiceFlags inFlags,
769 uint32_t inInterfaceIndex,
770 const char * inName,
771 uint16_t inRRType,
772 uint16_t inRRClass,
773 DNSServiceQueryRecordReply inCallBack,
774 void * inContext )
775 {
776 DNSServiceErrorType err;
777
778 #if( DNS_SD_CLIENT_ENABLED )
779 if( gDNSSDServerCompatible )
780 {
781 err = DNSServiceQueryRecord_client( outRef, gDNSSDServer, inFlags, inInterfaceIndex, inName, inRRType, inRRClass,
782 inCallBack, inContext );
783 goto exit;
784 }
785 #endif
786
787 #if( DNS_SD_DIRECT_ENABLED )
788 err = DNSServiceQueryRecord_direct( outRef, inFlags, inInterfaceIndex, inName, inRRType, inRRClass,
789 inCallBack, inContext );
790 goto exit;
791 #else
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 );
801
802 err = kUnsupportedErr;
803 goto exit;
804 #endif
805
806 exit:
807 return( err );
808 }
809
810 //===========================================================================================================================
811 // DNSServiceReconfirmRecord
812 //===========================================================================================================================
813
814 void
815 DNSServiceReconfirmRecord(
816 DNSServiceFlags inFlags,
817 uint32_t inInterfaceIndex,
818 const char * inName,
819 uint16_t inRRType,
820 uint16_t inRRClass,
821 uint16_t inRDataSize,
822 const void * inRData )
823 {
824 #if( DNS_SD_CLIENT_ENABLED )
825 if( gDNSSDServerCompatible )
826 {
827 DNSServiceReconfirmRecord_client( gDNSSDServer, inFlags, inInterfaceIndex, inName, inRRType, inRRClass,
828 inRDataSize, inRData );
829 goto exit;
830 }
831 #endif
832
833 #if( DNS_SD_DIRECT_ENABLED )
834 DNSServiceReconfirmRecord_direct( inFlags, inInterfaceIndex, inName, inRRType, inRRClass, inRDataSize, inRData );
835 goto exit;
836 #else
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 );
844
845 goto exit;
846 #endif
847
848 exit:
849 return;
850 }
851
852 #if 0
853 #pragma mark -
854 #pragma mark == Utilities ==
855 #endif
856
857 //===========================================================================================================================
858 // DomainEndsInDot
859 //
860 // Copied from dnssd_clientstub.c.
861 //===========================================================================================================================
862
863 DEBUG_LOCAL int DomainEndsInDot( const char *dom )
864 {
865 check( dom );
866
867 while(*dom && *(dom + 1))
868 {
869 if (*dom == '\\') // advance past escaped byte sequence
870 {
871 if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
872 else dom += 2;
873 }
874 else dom++; // else read one character
875 }
876 return (*dom == '.');
877 }
878
879 #if 0
880 #pragma mark -
881 #pragma mark == TXT Record Building ==
882 #endif
883
884 //===========================================================================================================================
885 // Structures
886 //===========================================================================================================================
887
888 typedef struct _TXTRecordRef_t _TXTRecordRef_t;
889 struct _TXTRecordRef_t
890 {
891 uint8_t * txt;
892 uint16_t size;
893 };
894
895 //===========================================================================================================================
896 // Prototypes
897 //===========================================================================================================================
898
899 DEBUG_LOCAL DNSServiceErrorType
900 TXTRecordGetValuePtrInternal(
901 uint16_t inTXTSize,
902 const void * inTXTBytes,
903 const char * inKey,
904 uint8_t ** outItem,
905 uint16_t * outItemSize,
906 const void ** outValue,
907 uint8_t * outValueSize );
908
909 DEBUG_LOCAL DNSServiceErrorType
910 TXTRecordGetItemAtIndexInternal(
911 uint16_t inTXTSize,
912 const void * inTXTBytes,
913 uint16_t inIndex,
914 uint8_t ** outItem,
915 uint16_t * outItemSize,
916 char * inKeyBuffer,
917 const void ** outValue,
918 uint8_t * outValueSize );
919
920 DEBUG_LOCAL int TXTRecordMemEqv( const void *inLeft, size_t inLeftSize, const void *inRight, size_t inRightSize );
921
922 //===========================================================================================================================
923 // TXTRecordCreate
924 //===========================================================================================================================
925
926 DNSServiceErrorType TXTRecordCreate( TXTRecordRef *outRef )
927 {
928 DNSServiceErrorType err;
929 TXTRecordRef obj;
930
931 require_action_expect( outRef, exit, err = kDNSServiceErr_BadParam );
932
933 obj = (TXTRecordRef) calloc( 1, sizeof( *obj ) );
934 require_action( obj, exit, err = kDNSServiceErr_NoMemory );
935
936 *outRef = obj;
937 err = kDNSServiceErr_NoError;
938
939 exit:
940 return( err );
941 }
942
943 //===========================================================================================================================
944 // TXTRecordDeallocate
945 //===========================================================================================================================
946
947 void TXTRecordDeallocate( TXTRecordRef inRef )
948 {
949 check( inRef );
950 if( inRef )
951 {
952 if( inRef->txt ) free( inRef->txt );
953 free( inRef );
954 }
955 }
956
957 //===========================================================================================================================
958 // TXTRecordSetValue
959 //===========================================================================================================================
960
961 DNSServiceErrorType TXTRecordSetValue( TXTRecordRef inRef, const char *inKey, uint8_t inValueSize, const void *inValue )
962 {
963 DNSServiceErrorType err;
964 const char * p;
965 size_t keySize;
966 uint8_t * item;
967 uint8_t * itemEnd;
968 uintptr_t itemOffset;
969 uint16_t oldItemSize;
970 uint16_t newItemSize;
971 uint16_t delta;
972 uint8_t * txt;
973
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 );
977
978 // Make sure the key is printable US-ASCII values (0x20-0x7E), excluding '=' (0x3D).
979
980 for( p = inKey; *p != '\0'; ++p )
981 {
982 if( ( *p < 0x20 ) || ( *p > 0x7E ) || ( *p == 0x3D ) )
983 {
984 break;
985 }
986 }
987 keySize = (size_t)( p - inKey );
988 require_action( ( keySize > 0 ) && ( keySize <= 255 ) && ( *p == '\0' ), exit, err = kDNSServiceErr_Invalid );
989
990 // Make sure the total item size does not exceed 255 bytes.
991
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 );
996
997 // Search for an existing item with the same key. If found, replace its value. Otherwise, append a new item.
998
999 err = TXTRecordGetValuePtrInternal( inRef->size, inRef->txt, inKey, &item, &oldItemSize, NULL, NULL );
1000 if( err == kDNSServiceErr_NoError )
1001 {
1002 if( newItemSize > oldItemSize )
1003 {
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.
1006
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 );
1011
1012 item = txt + itemOffset;
1013 itemEnd = item + ( 1 + oldItemSize );
1014 memmove( item + ( 1 + newItemSize ), itemEnd, (size_t)( ( inRef->txt + inRef->size ) - itemEnd ) );
1015 inRef->txt = txt;
1016 inRef->size = (uint16_t)( inRef->size + delta );
1017 }
1018 else if( newItemSize < oldItemSize )
1019 {
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.
1022
1023 itemEnd = item + ( 1 + oldItemSize );
1024 memmove( item + ( 1 + newItemSize ), itemEnd, (size_t)( ( inRef->txt + inRef->size ) - itemEnd ) );
1025
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 );
1030
1031 item = txt + itemOffset;
1032 inRef->txt = txt;
1033 }
1034 }
1035 else
1036 {
1037 // Resize the buffer to hold the new item.
1038
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 );
1042
1043 item = txt + inRef->size;
1044 inRef->txt = txt;
1045 inRef->size = (uint16_t)( inRef->size + delta );
1046 }
1047
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.
1050
1051 *item++ = (uint8_t) newItemSize;
1052 memcpy( item, inKey, keySize );
1053 item += keySize;
1054 if( inValue ) *item++ = '='; // Add '=' (only if there is a non-NULL value)
1055 memcpy( item, inValue, inValueSize );
1056 err = kDNSServiceErr_NoError;
1057
1058 exit:
1059 return( err );
1060 }
1061
1062 //===========================================================================================================================
1063 // TXTRecordRemoveValue
1064 //===========================================================================================================================
1065
1066 DNSServiceErrorType TXTRecordRemoveValue( TXTRecordRef inRef, const char *inKey )
1067 {
1068 DNSServiceErrorType err;
1069 uint8_t * item;
1070 uint8_t * itemEnd;
1071 uint16_t size;
1072 uint8_t * txt;
1073 uint8_t * txtEnd;
1074
1075 err = TXTRecordGetValuePtrInternal( inRef->size, inRef->txt, inKey, &item, &size, NULL, NULL );
1076 require_noerr_quiet( err, exit );
1077
1078 // Shift subsequent item(s) back to take up the slack of removing the item.
1079
1080 itemEnd = item + ( 1 + size );
1081 txtEnd = inRef->txt + inRef->size;
1082 if( itemEnd < txtEnd )
1083 {
1084 memmove( item, itemEnd, (size_t)( txtEnd - itemEnd ) );
1085 }
1086
1087 // Shrink the buffer to fit. If size goes to 0, use free because realloc with size 0 is not consistent across platforms.
1088
1089 inRef->size = (uint16_t)( inRef->size - ( (uint16_t)( itemEnd - item ) ) );
1090 if( inRef->size > 0 )
1091 {
1092 txt = (uint8_t *) realloc( inRef->txt, inRef->size );
1093 require_action_quiet( txt, exit, err = kDNSServiceErr_Unknown );
1094 }
1095 else
1096 {
1097 free( inRef->txt );
1098 txt = NULL;
1099 }
1100 inRef->txt = txt;
1101
1102 exit:
1103 return( err );
1104 }
1105
1106 //===========================================================================================================================
1107 // TXTRecordGetLength
1108 //===========================================================================================================================
1109
1110 uint16_t TXTRecordGetLength( TXTRecordRef inRef )
1111 {
1112 check( inRef );
1113
1114 if( inRef && inRef->txt )
1115 {
1116 return( inRef->size );
1117 }
1118 return( 0 );
1119 }
1120
1121 //===========================================================================================================================
1122 // TXTRecordGetBytesPtr
1123 //===========================================================================================================================
1124
1125 const void * TXTRecordGetBytesPtr( TXTRecordRef inRef )
1126 {
1127 check( inRef );
1128
1129 if( inRef && inRef->txt )
1130 {
1131 return( inRef->txt );
1132 }
1133 return( NULL );
1134 }
1135
1136 #if 0
1137 #pragma mark -
1138 #pragma mark == TXT Record Parsing ==
1139 #endif
1140
1141 //===========================================================================================================================
1142 // TXTRecordGetValuePtr
1143 //===========================================================================================================================
1144
1145 DNSServiceErrorType
1146 TXTRecordGetValuePtr(
1147 uint16_t inTXTSize,
1148 const void * inTXTBytes,
1149 const char * inKey,
1150 const void ** outValue,
1151 uint8_t * outValueSize )
1152 {
1153 return( TXTRecordGetValuePtrInternal( inTXTSize, inTXTBytes, inKey, NULL, NULL, outValue, outValueSize ) );
1154 }
1155
1156 //===========================================================================================================================
1157 // TXTRecordGetCount
1158 //===========================================================================================================================
1159
1160 uint16_t TXTRecordGetCount( uint16_t inTXTSize, const void *inTXTBytes )
1161 {
1162 uint16_t n;
1163 const uint8_t * p;
1164 const uint8_t * q;
1165
1166 require_action( inTXTBytes, exit, n = 0 );
1167
1168 n = 0;
1169 p = (const uint8_t *) inTXTBytes;
1170 q = p + inTXTSize;
1171 while( p < q )
1172 {
1173 ++n;
1174 p += ( 1 + *p );
1175 require_action( p <= q, exit, n = 0 );
1176 }
1177
1178 exit:
1179 return( n );
1180 }
1181
1182 //===========================================================================================================================
1183 // TXTRecordGetItemAtIndex
1184 //===========================================================================================================================
1185
1186 DNSServiceErrorType
1187 TXTRecordGetItemAtIndex(
1188 uint16_t inTXTSize,
1189 const void * inTXTBytes,
1190 uint16_t inIndex,
1191 char * inKeyBuffer,
1192 const void ** outValue,
1193 uint8_t * outValueSize )
1194 {
1195 return( TXTRecordGetItemAtIndexInternal( inTXTSize, inTXTBytes, inIndex, NULL, NULL, inKeyBuffer, outValue, outValueSize ) );
1196 }
1197
1198 #if 0
1199 #pragma mark -
1200 #pragma mark == TXT Record Internal ==
1201 #endif
1202
1203 //===========================================================================================================================
1204 // TXTRecordGetValuePtrInternal
1205 //===========================================================================================================================
1206
1207 DEBUG_LOCAL DNSServiceErrorType
1208 TXTRecordGetValuePtrInternal(
1209 uint16_t inTXTSize,
1210 const void * inTXTBytes,
1211 const char * inKey,
1212 uint8_t ** outItem,
1213 uint16_t * outItemSize,
1214 const void ** outValue,
1215 uint8_t * outValueSize )
1216 {
1217 DNSServiceErrorType err;
1218 size_t keySize;
1219 const uint8_t * p;
1220 const uint8_t * q;
1221 const uint8_t * r;
1222 const uint8_t * key;
1223 const uint8_t * keyEnd;
1224 const uint8_t * value;
1225 const uint8_t * valueEnd;
1226
1227 require_action_quiet( inTXTBytes, exit, err = kDNSServiceErr_NoSuchKey );
1228 require_action_expect( inKey, exit, err = kDNSServiceErr_BadParam );
1229 keySize = strlen( inKey );
1230
1231 // The following initializations are not necessary, but some compilers warn because they cannot detect it.
1232
1233 keyEnd = NULL;
1234 value = NULL;
1235 valueEnd = NULL;
1236
1237 // Find the item with the specified key.
1238
1239 p = (const uint8_t *) inTXTBytes;
1240 q = p + inTXTSize;
1241 while( p < q )
1242 {
1243 // Parse the key/value tokens. No '=' means the key takes up the entire item.
1244
1245 r = p + ( 1 + *p );
1246 require_action( r <= q, exit, err = kDNSServiceErr_Invalid );
1247
1248 key = p + 1;
1249 keyEnd = (const uint8_t *) memchr( key, '=', *p );
1250 if( keyEnd )
1251 {
1252 value = keyEnd + 1;
1253 }
1254 else
1255 {
1256 keyEnd = r;
1257 value = r;
1258 }
1259 valueEnd = r;
1260 if( TXTRecordMemEqv( key, (size_t)( keyEnd - key ), inKey, keySize ) == 0 )
1261 {
1262 break;
1263 }
1264
1265 p = r;
1266 check( p <= q );
1267 }
1268 require_action_quiet( p < q, exit, err = kDNSServiceErr_NoSuchKey );
1269
1270 // Fill in the results the caller wants.
1271
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;
1277
1278 exit:
1279 return( err );
1280 }
1281
1282 //===========================================================================================================================
1283 // TXTRecordGetItemAtIndexInternal
1284 //===========================================================================================================================
1285
1286 DEBUG_LOCAL DNSServiceErrorType
1287 TXTRecordGetItemAtIndexInternal(
1288 uint16_t inTXTSize,
1289 const void * inTXTBytes,
1290 uint16_t inIndex,
1291 uint8_t ** outItem,
1292 uint16_t * outItemSize,
1293 char * inKeyBuffer,
1294 const void ** outValue,
1295 uint8_t * outValueSize )
1296 {
1297 DNSServiceErrorType err;
1298 uint16_t n;
1299 const uint8_t * p;
1300 const uint8_t * q;
1301 const uint8_t * r;
1302 const uint8_t * key;
1303 const uint8_t * keyEnd;
1304 const uint8_t * value;
1305 const uint8_t * valueEnd;
1306
1307 require_action_quiet( inTXTBytes, exit, err = kDNSServiceErr_Invalid );
1308
1309 // Find the Nth item in the TXT record.
1310
1311 n = 0;
1312 p = (const uint8_t *) inTXTBytes;
1313 q = p + inTXTSize;
1314 while( p < q )
1315 {
1316 if( n == inIndex ) break;
1317 ++n;
1318
1319 p += ( 1 + *p );
1320 require_action( p <= q, exit, err = kDNSServiceErr_Invalid );
1321 }
1322 require_action_quiet( p < q, exit, err = kDNSServiceErr_Invalid );
1323
1324 // Item found. Parse the key/value tokens. No '=' means the key takes up the entire item.
1325
1326 r = p + ( 1 + *p );
1327 require_action( r <= q, exit, err = kDNSServiceErr_Invalid );
1328
1329 key = p + 1;
1330 keyEnd = (const uint8_t *) memchr( key, '=', *p );
1331 if( keyEnd )
1332 {
1333 value = keyEnd + 1;
1334 }
1335 else
1336 {
1337 keyEnd = r;
1338 value = r;
1339 }
1340 valueEnd = r;
1341
1342 // Fill in the results the caller wants.
1343
1344 if( outItem ) *outItem = (uint8_t *) p;
1345 if( outItemSize ) *outItemSize = *p;
1346 if( inKeyBuffer )
1347 {
1348 n = (uint16_t)( keyEnd - key );
1349 memcpy( inKeyBuffer, key, n );
1350 inKeyBuffer[ n ] = '\0';
1351 }
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;
1355
1356 exit:
1357 return( err );
1358 }
1359
1360 //===========================================================================================================================
1361 // TXTRecordMemEqv
1362 //===========================================================================================================================
1363
1364 DEBUG_LOCAL int TXTRecordMemEqv( const void *inLeft, size_t inLeftSize, const void *inRight, size_t inRightSize )
1365 {
1366 const uint8_t * p1;
1367 const uint8_t * p2;
1368 const uint8_t * end;
1369 int c1;
1370 int c2;
1371
1372 if( inLeftSize < inRightSize ) return( -1 );
1373 if( inLeftSize > inRightSize ) return( 1 );
1374
1375 p1 = (const uint8_t *) inLeft;
1376 p2 = (const uint8_t *) inRight;
1377 end = p1 + inLeftSize;
1378 while( p1 < end )
1379 {
1380 c1 = tolower( *p1 );
1381 c2 = tolower( *p2 );
1382 if( c1 < c2 ) return( -1 );
1383 if( c1 > c2 ) return( 1 );
1384
1385 ++p1;
1386 ++p2;
1387 }
1388 return( 0 );
1389 }
1390
1391 #if( DEBUG )
1392 //===========================================================================================================================
1393 // TXTRecordTest
1394 //===========================================================================================================================
1395
1396 DNSServiceErrorType TXTRecordTest( void );
1397
1398 DNSServiceErrorType TXTRecordTest( void )
1399 {
1400 DNSServiceErrorType err;
1401 const char * s;
1402 TXTRecordRef ref;
1403 const void * txt;
1404 uint16_t size;
1405 uint16_t n;
1406 char key[ 256 ];
1407 const void * value;
1408 uint8_t valueSize;
1409
1410 // Create Existing Test
1411
1412 s = "\014Anon Allowed"
1413 "\010Options="
1414 "\025InstalledPlugins=JPEG";
1415 size = (uint16_t) strlen( s );
1416
1417 n = TXTRecordGetCount( size, s );
1418 require_action( n == 3, exit, err = kDNSServiceErr_Unknown );
1419
1420 err = TXTRecordGetValuePtr( size, s, "test", NULL, NULL );
1421 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1422
1423 err = TXTRecordGetValuePtr( size, s, "Anon", NULL, NULL );
1424 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1425
1426 err = TXTRecordGetValuePtr( size, s, "Allowed", NULL, NULL );
1427 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1428
1429 err = TXTRecordGetValuePtr( size, s, "", NULL, NULL );
1430 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1431
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 );
1436
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 );
1441
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 );
1446
1447 key[ 0 ] = '\0';
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 );
1453
1454 key[ 0 ] = '\0';
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 );
1460
1461 key[ 0 ] = '\0';
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 );
1468
1469 key[ 0 ] = '\0';
1470 err = TXTRecordGetItemAtIndex( size, s, 3, key, &value, &valueSize );
1471 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1472
1473 // Empty Test
1474
1475 err = TXTRecordCreate( &ref );
1476 require_noerr( err, exit );
1477
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 );
1482
1483 TXTRecordDeallocate( ref );
1484
1485 // Create Single Test
1486
1487 err = TXTRecordCreate( &ref );
1488 require_noerr( err, exit );
1489
1490 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1491 require_noerr( err, exit );
1492
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 );
1498
1499 n = TXTRecordGetCount( size, txt );
1500 require_action( n == 1, exit, err = kDNSServiceErr_Unknown );
1501
1502 err = TXTRecordGetValuePtr( size, txt, "test", NULL, NULL );
1503 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1504
1505 err = TXTRecordGetValuePtr( size, txt, "Anon", NULL, NULL );
1506 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1507
1508 err = TXTRecordGetValuePtr( size, txt, "Allowed", NULL, NULL );
1509 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1510
1511 err = TXTRecordGetValuePtr( size, txt, "", NULL, NULL );
1512 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1513
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 );
1518
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 );
1523
1524 TXTRecordDeallocate( ref );
1525
1526 // Create Multiple Test
1527
1528 err = TXTRecordCreate( &ref );
1529 require_noerr( err, exit );
1530
1531 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1532 require_noerr( err, exit );
1533
1534 err = TXTRecordSetValue( ref, "Options", 0, "" );
1535 require_noerr( err, exit );
1536
1537 err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
1538 require_noerr( err, exit );
1539
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,
1545 "\014Anon Allowed"
1546 "\010Options="
1547 "\025InstalledPlugins=JPEG",
1548 size ) == 0, exit, err = kDNSServiceErr_Unknown );
1549
1550 n = TXTRecordGetCount( size, txt );
1551 require_action( n == 3, exit, err = kDNSServiceErr_Unknown );
1552
1553 err = TXTRecordGetValuePtr( size, txt, "test", NULL, NULL );
1554 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1555
1556 err = TXTRecordGetValuePtr( size, txt, "Anon", NULL, NULL );
1557 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1558
1559 err = TXTRecordGetValuePtr( size, txt, "Allowed", NULL, NULL );
1560 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1561
1562 err = TXTRecordGetValuePtr( size, txt, "", NULL, NULL );
1563 require_action( err != kDNSServiceErr_NoError, exit, err = kDNSServiceErr_Unknown );
1564
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 );
1569
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 );
1574
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 );
1579
1580 TXTRecordDeallocate( ref );
1581
1582 // Remove Single Test
1583
1584 err = TXTRecordCreate( &ref );
1585 require_noerr( err, exit );
1586
1587 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1588 require_noerr( err, exit );
1589
1590 err = TXTRecordRemoveValue( ref, "Anon Allowed" );
1591 require_noerr( err, exit );
1592
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 );
1597
1598 TXTRecordDeallocate( ref );
1599
1600 // Remove Multiple Test
1601
1602 err = TXTRecordCreate( &ref );
1603 require_noerr( err, exit );
1604
1605 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1606 require_noerr( err, exit );
1607
1608 err = TXTRecordSetValue( ref, "Options", 0, "" );
1609 require_noerr( err, exit );
1610
1611 err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
1612 require_noerr( err, exit );
1613
1614 err = TXTRecordRemoveValue( ref, "Options" );
1615 require_noerr( err, exit );
1616
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,
1622 "\014Anon Allowed"
1623 "\025InstalledPlugins=JPEG",
1624 size ) == 0, exit, err = kDNSServiceErr_Unknown );
1625
1626 n = TXTRecordGetCount( size, txt );
1627 require_action( n == 2, exit, err = kDNSServiceErr_Unknown );
1628
1629 err = TXTRecordRemoveValue( ref, "Anon Allowed" );
1630 require_noerr( err, exit );
1631
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 );
1639
1640 n = TXTRecordGetCount( size, txt );
1641 require_action( n == 1, exit, err = kDNSServiceErr_Unknown );
1642
1643 err = TXTRecordRemoveValue( ref, "InstalledPlugins" );
1644 require_noerr( err, exit );
1645
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 );
1650
1651 TXTRecordDeallocate( ref );
1652
1653 // Replace Test
1654
1655 err = TXTRecordCreate( &ref );
1656 require_noerr( err, exit );
1657
1658 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1659 require_noerr( err, exit );
1660
1661 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1662 require_noerr( err, exit );
1663
1664 err = TXTRecordSetValue( ref, "Options", 0, "" );
1665 require_noerr( err, exit );
1666
1667 err = TXTRecordSetValue( ref, "Options", 0, "" );
1668 require_noerr( err, exit );
1669
1670 err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
1671 require_noerr( err, exit );
1672
1673 err = TXTRecordSetValue( ref, "InstalledPlugins", 4, "JPEG" );
1674 require_noerr( err, exit );
1675
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,
1681 "\014Anon Allowed"
1682 "\010Options="
1683 "\025InstalledPlugins=JPEG",
1684 size ) == 0, exit, err = kDNSServiceErr_Unknown );
1685
1686 err = TXTRecordSetValue( ref, "Anon Allowed", 4, "test" );
1687 require_noerr( err, exit );
1688
1689 err = TXTRecordSetValue( ref, "Anon Allowed", 0, "" );
1690 require_noerr( err, exit );
1691
1692 err = TXTRecordSetValue( ref, "Anon Allowed", 0, NULL );
1693 require_noerr( err, exit );
1694
1695 err = TXTRecordSetValue( ref, "Anon Allowed", 0, "" );
1696 require_noerr( err, exit );
1697
1698 err = TXTRecordSetValue( ref, "Anon Allowed", 4, "test" );
1699 require_noerr( err, exit );
1700
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"
1707 "\010Options="
1708 "\025InstalledPlugins=JPEG",
1709 size ) == 0, exit, err = kDNSServiceErr_Unknown );
1710
1711 TXTRecordDeallocate( ref );
1712
1713 exit:
1714 return( err );
1715 }
1716 #endif // DEBUG
1717
1718 #ifdef __cplusplus
1719 }
1720 #endif