1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 17 Contains: mDNS platform plugin for VxWorks. 18 19 Copyright: Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved. 20 21 Notes for non-Apple platforms: 22 23 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions. 24 25 To Do: 26 27 - Add support for IPv6 (needs VxWorks IPv6 support). 28 */ 29 30// Set up the debug library to use the default category (see DebugServicesLite.h for details). 31 32#if ( !TARGET_NON_APPLE ) 33 #define DEBUG_USE_DEFAULT_CATEGORY 1 34#endif 35 36#include <stdarg.h> 37#include <stddef.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41 42#include <sys/types.h> 43#include <arpa/inet.h> 44#include <fcntl.h> 45#include <netinet/if_ether.h> 46#include <netinet/in.h> 47#include <netinet/ip.h> 48#include <sys/ioctl.h> 49#include <sys/socket.h> 50#include <unistd.h> 51 52#include "vxWorks.h" 53#include "ifLib.h" 54#include "inetLib.h" 55#include "pipeDrv.h" 56#include "selectLib.h" 57#include "semLib.h" 58#include "sockLib.h" 59#include "sysLib.h" 60#include "taskLib.h" 61#include "tickLib.h" 62 63#include "config.h" 64 65#if ( !TARGET_NON_APPLE ) 66 #include "ACP/ACPUtilities.h" 67 #include "Support/DebugServicesLite.h" 68 #include "Support/MiscUtilities.h" 69#endif 70 71#include "mDNSEmbeddedAPI.h" 72 73#include "mDNSVxWorks.h" 74 75#if 0 76#pragma mark == Preprocessor == 77#endif 78 79//=========================================================================================================================== 80// Preprocessor 81//=========================================================================================================================== 82 83#if ( !TARGET_NON_APPLE ) 84debug_log_new_default_category( mdns ); 85#endif 86 87#if 0 88#pragma mark == Constants == 89#endif 90 91//=========================================================================================================================== 92// Constants 93//=========================================================================================================================== 94 95#define DEBUG_NAME "[mDNS] " 96 97#define kMDNSDefaultName "My-Device" 98 99#define kMDNSTaskName "tMDNS" 100#define kMDNSTaskPriority 102 101#define kMDNSTaskStackSize 49152 102 103#define kMDNSPipeName "/pipe/mDNS" 104#define kMDNSPipeMessageQueueSize 32 105#define kMDNSPipeMessageSize 1 106 107#define kInvalidSocketRef -1 108 109typedef uint8_t MDNSPipeCommandCode; 110enum 111{ 112 kMDNSPipeCommandCodeInvalid = 0, 113 kMDNSPipeCommandCodeReschedule = 1, 114 kMDNSPipeCommandCodeReconfigure = 2, 115 kMDNSPipeCommandCodeQuit = 3 116}; 117 118#if 0 119#pragma mark == Structures == 120#endif 121 122//=========================================================================================================================== 123// Structures 124//=========================================================================================================================== 125 126typedef int MDNSSocketRef; 127 128struct MDNSInterfaceItem 129{ 130 MDNSInterfaceItem * next; 131 char name[ 32 ]; 132 MDNSSocketRef multicastSocketRef; 133 MDNSSocketRef sendingSocketRef; 134 NetworkInterfaceInfo hostSet; 135 mDNSBool hostRegistered; 136 137 int sendMulticastCounter; 138 int sendUnicastCounter; 139 int sendErrorCounter; 140 141 int recvCounter; 142 int recvErrorCounter; 143 int recvLoopCounter; 144}; 145 146#if 0 147#pragma mark == Macros == 148#endif 149 150//=========================================================================================================================== 151// Macros 152//=========================================================================================================================== 153 154#if ( TARGET_NON_APPLE ) 155 156// Do-nothing versions of the debugging macros for non-Apple platforms. 157 158 #define check(assertion) 159 #define check_string( assertion, cstring ) 160 #define check_noerr(err) 161 #define check_noerr_string( error, cstring ) 162 #define check_errno( assertion, errno_value ) 163 #define debug_string( cstring ) 164 #define require( assertion, label ) do { if( !(assertion) ) goto label;} while(0) 165 #define require_string( assertion, label, string ) require(assertion, label) 166 #define require_quiet( assertion, label ) require( assertion, label ) 167 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label;} while(0) 168 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label ) 169 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0) 170 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action ) 171 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0) 172 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action ) 173 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0) 174 #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label;} while(0) 175 #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0) 176 177 #define dlog( ARGS... ) 178 179 #define DEBUG_UNUSED( X ) (void)( X ) 180#endif 181 182#if 0 183#pragma mark == Prototypes == 184#endif 185 186//=========================================================================================================================== 187// Prototypes 188//=========================================================================================================================== 189 190// ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here. 191 192extern struct ifnet * ifIndexToIfp(int ifIndex); 193 194// Platform Internals 195 196mDNSlocal void SetupNames( mDNS * const inMDNS ); 197mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS ); 198mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS ); 199mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem ); 200mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem ); 201mDNSlocal mStatus 202SetupSocket( 203 mDNS * const inMDNS, 204 const struct ifaddrs * inAddr, 205 mDNSIPPort inPort, 206 MDNSSocketRef * outSocketRef ); 207 208// Commands 209 210mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS ); 211mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS ); 212mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode ); 213mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS ); 214mDNSlocal void ProcessCommandReconfigure( mDNS *inMDNS ); 215 216// Threads 217 218mDNSlocal mStatus SetupTask( mDNS * const inMDNS ); 219mDNSlocal mStatus TearDownTask( mDNS * const inMDNS ); 220mDNSlocal void Task( mDNS *inMDNS ); 221mDNSlocal mStatus TaskInit( mDNS *inMDNS ); 222mDNSlocal void TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket ); 223mDNSlocal void TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout ); 224mDNSlocal void TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef ); 225 226// Utilities 227 228#if ( TARGET_NON_APPLE ) 229mDNSlocal void GenerateUniqueHostName( char *outName, long *ioSeed ); 230mDNSlocal void GenerateUniqueDNSName( char *outName, long *ioSeed ); 231#endif 232 233// Platform Accessors 234 235#ifdef __cplusplus 236extern "C" { 237#endif 238 239typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo; 240struct mDNSPlatformInterfaceInfo 241{ 242 const char * name; 243 mDNSAddr ip; 244}; 245 246mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID ); 247mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo ); 248 249#ifdef __cplusplus 250} 251#endif 252 253#if 0 254#pragma mark == Globals == 255#endif 256 257//=========================================================================================================================== 258// Globals 259//=========================================================================================================================== 260 261mDNSlocal mDNS * gMDNSPtr = NULL; 262mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport; 263mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier = 0; 264 265// Platform support 266 267mDNSs32 mDNSPlatformOneSecond; 268 269#if 0 270#pragma mark - 271#pragma mark == Public APIs == 272#endif 273 274//=========================================================================================================================== 275// mDNSReconfigure 276//=========================================================================================================================== 277 278void mDNSReconfigure( void ) 279{ 280 // Send a "reconfigure" command to the MDNS task. 281 282 if( gMDNSPtr ) 283 { 284 SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure ); 285 } 286} 287 288#if 0 289#pragma mark - 290#pragma mark == Platform Support == 291#endif 292 293//=========================================================================================================================== 294// mDNSPlatformInit 295//=========================================================================================================================== 296 297mStatus mDNSPlatformInit( mDNS * const inMDNS ) 298{ 299 mStatus err; 300 301 dlog( kDebugLevelInfo, DEBUG_NAME "platform init\n" ); 302 303 // Initialize variables. 304 305 mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) ); 306 inMDNS->p = &gMDNSPlatformSupport; 307 inMDNS->p->commandPipe = ERROR; 308 inMDNS->p->task = ERROR; 309 inMDNS->p->rescheduled = 1; // Default to rescheduled until fully initialized. 310 mDNSPlatformOneSecond = sysClkRateGet(); 311 gMDNSTicksToMicrosecondsMultiplier = ( 1000000L / mDNSPlatformOneSecond ); 312 313 // Allocate semaphores. 314 315 inMDNS->p->lockID = semMCreate( SEM_Q_FIFO ); 316 require_action( inMDNS->p->lockID, exit, err = mStatus_NoMemoryErr ); 317 318 inMDNS->p->readyEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY ); 319 require_action( inMDNS->p->readyEvent, exit, err = mStatus_NoMemoryErr ); 320 321 inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY ); 322 require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr ); 323 324 gMDNSPtr = inMDNS; 325 326 // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid 327 // stack space issues. Some of the initialization may require a larger stack than the current task supports. 328 329 err = SetupTask( inMDNS ); 330 require_noerr( err, exit ); 331 332 err = semTake( inMDNS->p->readyEvent, WAIT_FOREVER ); 333 require_noerr( err, exit ); 334 err = inMDNS->p->taskInitErr; 335 require_noerr( err, exit ); 336 337 mDNSCoreInitComplete( inMDNS, err ); 338 339exit: 340 if( err ) 341 { 342 mDNSPlatformClose( inMDNS ); 343 } 344 dlog( kDebugLevelInfo, DEBUG_NAME "platform init done (err=%ld)\n", err ); 345 return( err ); 346} 347 348//=========================================================================================================================== 349// mDNSPlatformClose 350//=========================================================================================================================== 351 352void mDNSPlatformClose( mDNS * const inMDNS ) 353{ 354 mStatus err; 355 356 dlog( kDebugLevelInfo, DEBUG_NAME "platform close\n" ); 357 check( inMDNS ); 358 359 // Tear everything down. 360 361 err = TearDownTask( inMDNS ); 362 check_noerr( err ); 363 364 err = TearDownInterfaceList( inMDNS ); 365 check_noerr( err ); 366 367 err = TearDownCommandPipe( inMDNS ); 368 check_noerr( err ); 369 370 gMDNSPtr = NULL; 371 372 // Release semaphores. 373 374 if( inMDNS->p->quitEvent ) 375 { 376 semDelete( inMDNS->p->quitEvent ); 377 inMDNS->p->quitEvent = 0; 378 } 379 if( inMDNS->p->readyEvent ) 380 { 381 semDelete( inMDNS->p->readyEvent ); 382 inMDNS->p->readyEvent = 0; 383 } 384 if( inMDNS->p->lockID ) 385 { 386 semDelete( inMDNS->p->lockID ); 387 inMDNS->p->lockID = 0; 388 } 389 390 dlog( kDebugLevelInfo, DEBUG_NAME "platform close done\n" ); 391} 392 393//=========================================================================================================================== 394// mDNSPlatformSendUDP 395//=========================================================================================================================== 396 397mStatus 398mDNSPlatformSendUDP( 399 const mDNS * const inMDNS, 400 const void * const inMsg, 401 const mDNSu8 * const inMsgEnd, 402 mDNSInterfaceID inInterfaceID, 403 const mDNSAddr * inDstIP, 404 mDNSIPPort inDstPort ) 405{ 406 mStatus err; 407 MDNSInterfaceItem * item; 408 struct sockaddr_in addr; 409 int n; 410 411 dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP\n" ); 412 413 // Check parameters. 414 415 check( inMDNS ); 416 check( inMsg ); 417 check( inMsgEnd ); 418 check( inInterfaceID ); 419 check( inDstIP ); 420 if( inDstIP->type != mDNSAddrType_IPv4 ) 421 { 422 err = mStatus_BadParamErr; 423 goto exit; 424 } 425 426#if ( DEBUG ) 427 // Make sure the InterfaceID is valid. 428 429 for( item = inMDNS->p->interfaceList; item; item = item->next ) 430 { 431 if( item == (MDNSInterfaceItem *) inInterfaceID ) 432 { 433 break; 434 } 435 } 436 require_action( item, exit, err = mStatus_NoSuchNameErr ); 437#endif 438 439 // Send the packet. 440 441 item = (MDNSInterfaceItem *) inInterfaceID; 442 check( item->sendingSocketRef != kInvalidSocketRef ); 443 444 mDNSPlatformMemZero( &addr, sizeof( addr ) ); 445 addr.sin_family = AF_INET; 446 addr.sin_port = inDstPort.NotAnInteger; 447 addr.sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger; 448 449 n = inMsgEnd - ( (const mDNSu8 * const) inMsg ); 450 n = sendto( item->sendingSocketRef, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) ); 451 check_errno( n, errno ); 452 453 item->sendErrorCounter += ( n < 0 ); 454 item->sendMulticastCounter += ( inDstPort.NotAnInteger == MulticastDNSPort.NotAnInteger ); 455 item->sendUnicastCounter += ( inDstPort.NotAnInteger != MulticastDNSPort.NotAnInteger ); 456 457 dlog( kDebugLevelChatty, DEBUG_NAME "sent (to=%u.%u.%u.%u:%hu)\n", 458 inDstIP->ip.v4.b[ 0 ], inDstIP->ip.v4.b[ 1 ], inDstIP->ip.v4.b[ 2 ], inDstIP->ip.v4.b[ 3 ], 459 htons( inDstPort.NotAnInteger ) ); 460 err = mStatus_NoError; 461 462exit: 463 dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP done\n" ); 464 return( err ); 465} 466 467//=========================================================================================================================== 468// Connection-oriented (TCP) functions 469//=========================================================================================================================== 470 471mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, 472 TCPConnectionCallback callback, void *context, int *descriptor) 473{ 474 (void)dst; // Unused 475 (void)dstport; // Unused 476 (void)InterfaceID; // Unused 477 (void)callback; // Unused 478 (void)context; // Unused 479 (void)descriptor; // Unused 480 return(mStatus_UnsupportedErr); 481} 482 483mDNSexport void mDNSPlatformTCPCloseConnection(int sd) 484{ 485 (void)sd; // Unused 486} 487 488mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen) 489{ 490 (void)sd; // Unused 491 (void)buf; // Unused 492 (void)buflen; // Unused 493 return(0); 494} 495 496mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len) 497{ 498 (void)sd; // Unused 499 (void)msg; // Unused 500 (void)len; // Unused 501 return(0); 502} 503 504//=========================================================================================================================== 505// mDNSPlatformLock 506//=========================================================================================================================== 507 508void mDNSPlatformLock( const mDNS * const inMDNS ) 509{ 510 check( inMDNS->p->lockID ); 511 512 if( inMDNS->p->lockID ) 513 { 514 #if ( TARGET_NON_APPLE ) 515 semTake( inMDNS->p->lockID, WAIT_FOREVER ); 516 #else 517 semTakeDeadlockDetect( inMDNS->p->lockID, WAIT_FOREVER ); 518 #endif 519 } 520} 521 522//=========================================================================================================================== 523// mDNSPlatformUnlock 524//=========================================================================================================================== 525 526void mDNSPlatformUnlock( const mDNS * const inMDNS ) 527{ 528 check( inMDNS ); 529 check( inMDNS->p ); 530 check( inMDNS->p->lockID ); 531 check_string( inMDNS->p->task != ERROR, "mDNS task not started" ); 532 533 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock() 534 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to: 535 // (a) handle immediate work (if any) resulting from this API call 536 // (b) calculate the next sleep time between now and the next interesting event 537 538 if( ( mDNS_TimeNow(inMDNS) - inMDNS->NextScheduledEvent ) >= 0 ) 539 { 540 // We only need to send the reschedule event when called from a task other than the mDNS task since if we are 541 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue. 542 543 if( ( inMDNS->p->rescheduled++ == 0 ) && ( taskIdSelf() != inMDNS->p->task ) ) 544 { 545 SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule ); 546 } 547 } 548 549 if( inMDNS->p->lockID ) 550 { 551 semGive( inMDNS->p->lockID ); 552 } 553} 554 555//=========================================================================================================================== 556// mDNSPlatformStrLen 557//=========================================================================================================================== 558 559mDNSu32 mDNSPlatformStrLen( const void *inSrc ) 560{ 561 check( inSrc ); 562 563 return( (mDNSu32) strlen( (const char *) inSrc ) ); 564} 565 566//=========================================================================================================================== 567// mDNSPlatformStrCopy 568//=========================================================================================================================== 569 570void mDNSPlatformStrCopy( void *inDst, const void *inSrc ) 571{ 572 check( inSrc ); 573 check( inDst ); 574 575 strcpy( (char *) inDst, (const char*) inSrc ); 576} 577 578//=========================================================================================================================== 579// mDNSPlatformMemCopy 580//=========================================================================================================================== 581 582void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize ) 583{ 584 check( inSrc ); 585 check( inDst ); 586 587 memcpy( inDst, inSrc, inSize ); 588} 589 590//=========================================================================================================================== 591// mDNSPlatformMemSame 592//=========================================================================================================================== 593 594mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize ) 595{ 596 check( inSrc ); 597 check( inDst ); 598 599 return( memcmp( inSrc, inDst, inSize ) == 0 ); 600} 601 602//=========================================================================================================================== 603// mDNSPlatformMemZero 604//=========================================================================================================================== 605 606void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize ) 607{ 608 check( inDst ); 609 610 memset( inDst, 0, inSize ); 611} 612 613//=========================================================================================================================== 614// mDNSPlatformMemAllocate 615//=========================================================================================================================== 616 617mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize ) 618{ 619 void * mem; 620 621 check( inSize > 0 ); 622 623 mem = malloc( inSize ); 624 check( mem ); 625 626 return( mem ); 627} 628 629//=========================================================================================================================== 630// mDNSPlatformMemFree 631//=========================================================================================================================== 632 633mDNSexport void mDNSPlatformMemFree( void *inMem ) 634{ 635 check( inMem ); 636 637 free( inMem ); 638} 639 640//=========================================================================================================================== 641// mDNSPlatformRandomSeed 642//=========================================================================================================================== 643 644mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) 645{ 646 return( tickGet() ); 647} 648 649//=========================================================================================================================== 650// mDNSPlatformTimeInit 651//=========================================================================================================================== 652 653mDNSexport mStatus mDNSPlatformTimeInit( void ) 654{ 655 // No special setup is required on VxWorks -- we just use tickGet(). 656 return( mStatus_NoError ); 657} 658 659//=========================================================================================================================== 660// mDNSPlatformRawTime 661//=========================================================================================================================== 662 663mDNSs32 mDNSPlatformRawTime( void ) 664{ 665 return( (mDNSs32) tickGet() ); 666} 667 668//=========================================================================================================================== 669// mDNSPlatformUTC 670//=========================================================================================================================== 671 672mDNSexport mDNSs32 mDNSPlatformUTC( void ) 673{ 674 return( -1 ); 675} 676 677//=========================================================================================================================== 678// mDNSPlatformInterfaceNameToID 679//=========================================================================================================================== 680 681mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID ) 682{ 683 mStatus err; 684 MDNSInterfaceItem * ifd; 685 686 check( inMDNS ); 687 check( inMDNS->p ); 688 check( inName ); 689 690 // Search for an interface with the specified name, 691 692 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next ) 693 { 694 if( strcmp( ifd->name, inName ) == 0 ) 695 { 696 break; 697 } 698 } 699 if( !ifd ) 700 { 701 err = mStatus_NoSuchNameErr; 702 goto exit; 703 } 704 705 // Success! 706 707 if( outID ) 708 { 709 *outID = (mDNSInterfaceID) ifd; 710 } 711 err = mStatus_NoError; 712 713exit: 714 return( err ); 715} 716 717//=========================================================================================================================== 718// mDNSPlatformInterfaceIDToInfo 719//=========================================================================================================================== 720 721mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo ) 722{ 723 mStatus err; 724 MDNSInterfaceItem * ifd; 725 726 check( inMDNS ); 727 check( inID ); 728 check( outInfo ); 729 730 // Search for an interface with the specified ID, 731 732 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next ) 733 { 734 if( ifd == (MDNSInterfaceItem *) inID ) 735 { 736 break; 737 } 738 } 739 if( !ifd ) 740 { 741 err = mStatus_NoSuchNameErr; 742 goto exit; 743 } 744 745 // Success! 746 747 outInfo->name = ifd->name; 748 outInfo->ip = ifd->hostSet.ip; 749 err = mStatus_NoError; 750 751exit: 752 return( err ); 753} 754 755//=========================================================================================================================== 756// debugf_ 757//=========================================================================================================================== 758 759#if ( MDNS_DEBUGMSGS ) 760mDNSexport void debugf_( const char *format, ... ) 761{ 762 char buffer[ 512 ]; 763 va_list args; 764 mDNSu32 length; 765 766 va_start( args, format ); 767 length = mDNS_vsnprintf( buffer, sizeof( buffer ), format, args ); 768 va_end( args ); 769 770 dlog( kDebugLevelInfo, "%s\n", buffer ); 771} 772#endif 773 774//=========================================================================================================================== 775// verbosedebugf_ 776//=========================================================================================================================== 777 778#if ( MDNS_DEBUGMSGS > 1 ) 779mDNSexport void verbosedebugf_( const char *format, ... ) 780{ 781 char buffer[ 512 ]; 782 va_list args; 783 mDNSu32 length; 784 785 va_start( args, format ); 786 length = mDNS_vsnprintf( buffer, sizeof( buffer ), format, args ); 787 va_end( args ); 788 789 dlog( kDebugLevelVerbose, "%s\n", buffer ); 790} 791#endif 792 793//=========================================================================================================================== 794// LogMsg 795//=========================================================================================================================== 796 797void LogMsg( const char *inFormat, ... ) 798{ 799 char buffer[ 512 ]; 800 va_list args; 801 mDNSu32 length; 802 803 va_start( args, inFormat ); 804 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args ); 805 va_end( args ); 806 807 dlog( kDebugLevelWarning, "%s\n", buffer ); 808} 809 810#if 0 811#pragma mark - 812#pragma mark == Platform Internals == 813#endif 814 815//=========================================================================================================================== 816// SetupNames 817//=========================================================================================================================== 818 819mDNSlocal void SetupNames( mDNS * const inMDNS ) 820{ 821 char tempCString[ 128 ]; 822 mDNSu8 tempPString[ 128 ]; 823 mDNSu8 * namePtr; 824 825 // Set up the host name. 826 827 tempCString[ 0 ] = '\0'; 828 GenerateUniqueHostName( tempCString, NULL ); 829 check( tempCString[ 0 ] != '\0' ); 830 if( tempCString[ 0 ] == '\0' ) 831 { 832 // No name so use the default. 833 834 strcpy( tempCString, kMDNSDefaultName ); 835 } 836 inMDNS->nicelabel.c[ 0 ] = strlen( tempCString ); 837 memcpy( &inMDNS->nicelabel.c[ 1 ], tempCString, inMDNS->nicelabel.c[ 0 ] ); 838 check( inMDNS->nicelabel.c[ 0 ] > 0 ); 839 840 // Set up the DNS name. 841 842 tempCString[ 0 ] = '\0'; 843 GenerateUniqueDNSName( tempCString, NULL ); 844 if( tempCString[ 0 ] != '\0' ) 845 { 846 tempPString[ 0 ] = strlen( tempCString ); 847 memcpy( &tempPString[ 1 ], tempCString, tempPString[ 0 ] ); 848 namePtr = tempPString; 849 } 850 else 851 { 852 // No DNS name so use the host name. 853 854 namePtr = inMDNS->nicelabel.c; 855 } 856 ConvertUTF8PstringToRFC1034HostLabel( namePtr, &inMDNS->hostlabel ); 857 if( inMDNS->hostlabel.c[ 0 ] == 0 ) 858 { 859 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default. 860 861 MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName ); 862 } 863 check( inMDNS->hostlabel.c[ 0 ] > 0 ); 864 865 mDNS_SetFQDN( inMDNS ); 866 867 dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] ); 868 dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] ); 869} 870 871//=========================================================================================================================== 872// SetupInterfaceList 873//=========================================================================================================================== 874 875mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS ) 876{ 877 mStatus err; 878 struct ifaddrs * addrs; 879 struct ifaddrs * p; 880 uint32_t flagMask; 881 uint32_t flagTest; 882 MDNSInterfaceItem ** next; 883 MDNSInterfaceItem * item; 884 885 addrs = NULL; 886 887 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list\n" ); 888 check( inMDNS ); 889 890 // Tear down any existing interfaces that may be set up. 891 892 TearDownInterfaceList( inMDNS ); 893 inMDNS->p->interfaceList = NULL; 894 next = &inMDNS->p->interfaceList; 895 896 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point. 897 898 flagMask = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTOPOINT; 899 flagTest = IFF_UP | IFF_MULTICAST; 900 901 err = getifaddrs( &addrs ); 902 require_noerr( err, exit ); 903 904 for( p = addrs; p; p = p->ifa_next ) 905 { 906 if( ( p->ifa_flags & flagMask ) == flagTest ) 907 { 908 err = SetupInterface( inMDNS, p, &item ); 909 require_noerr( err, exit ); 910 911 *next = item; 912 next = &item->next; 913 } 914 } 915 err = mStatus_NoError; 916 917exit: 918 if( addrs ) 919 { 920 freeifaddrs( addrs ); 921 } 922 if( err ) 923 { 924 TearDownInterfaceList( inMDNS ); 925 } 926 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list done (err=%ld)\n", err ); 927 return( err ); 928} 929 930//=========================================================================================================================== 931// TearDownInterfaceList 932//=========================================================================================================================== 933 934mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS ) 935{ 936 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list\n" ); 937 check( inMDNS ); 938 939 // Tear down all the interfaces. 940 941 while( inMDNS->p->interfaceList ) 942 { 943 MDNSInterfaceItem * item; 944 945 item = inMDNS->p->interfaceList; 946 inMDNS->p->interfaceList = item->next; 947 948 TearDownInterface( inMDNS, item ); 949 } 950 951 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list done\n" ); 952 return( mStatus_NoError ); 953} 954 955//=========================================================================================================================== 956// SetupInterface 957//=========================================================================================================================== 958 959mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem ) 960{ 961 mStatus err; 962 MDNSInterfaceItem * item; 963 MDNSSocketRef socketRef; 964 const struct sockaddr_in * ipv4, *mask; 965 966 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface (name=%s)\n", inAddr->ifa_name ); 967 check( inMDNS ); 968 check( inAddr ); 969 check( inAddr->ifa_addr ); 970 ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr; 971 mask = (const struct sockaddr_in *) inAddr->ifa_netmask; 972 check( outItem ); 973 974 // Allocate memory for the info item. 975 976 item = (MDNSInterfaceItem *) calloc( 1, sizeof( *item ) ); 977 require_action( item, exit, err = mStatus_NoMemoryErr ); 978 strcpy( item->name, inAddr->ifa_name ); 979 item->multicastSocketRef = kInvalidSocketRef; 980 item->sendingSocketRef = kInvalidSocketRef; 981 982 // Set up the multicast DNS (port 5353) socket for this interface. 983 984 err = SetupSocket( inMDNS, inAddr, MulticastDNSPort, &socketRef ); 985 require_noerr( err, exit ); 986 item->multicastSocketRef = socketRef; 987 988 // Set up the sending socket for this interface. 989 990 err = SetupSocket( inMDNS, inAddr, zeroIPPort, &socketRef ); 991 require_noerr( err, exit ); 992 item->sendingSocketRef = socketRef; 993 994 // Register this interface with mDNS. 995 996 item->hostSet.InterfaceID = (mDNSInterfaceID) item; 997 item->hostSet.ip.type = mDNSAddrType_IPv4; 998 item->hostSet.ip.ip.v4.NotAnInteger = ipv4->sin_addr.s_addr; 999 item->hostSet.mask.type = mDNSAddrType_IPv4; 1000 item->hostSet.mask.ip.v4.NotAnInteger = mask->sin_addr.s_addr; 1001 item->hostSet.ifname[0] = 0; 1002 item->hostSet.Advertise = inMDNS->AdvertiseLocalAddresses; 1003 item->hostSet.McastTxRx = mDNStrue; 1004 1005 err = mDNS_RegisterInterface( inMDNS, &item->hostSet, mDNSfalse ); 1006 require_noerr( err, exit ); 1007 item->hostRegistered = mDNStrue; 1008 1009 dlog( kDebugLevelInfo, DEBUG_NAME "Registered IP address: %u.%u.%u.%u\n", 1010 item->hostSet.ip.ip.v4.b[ 0 ], item->hostSet.ip.ip.v4.b[ 1 ], 1011 item->hostSet.ip.ip.v4.b[ 2 ], item->hostSet.ip.ip.v4.b[ 3 ] ); 1012 1013 // Success! 1014 1015 *outItem = item; 1016 item = NULL; 1017 1018exit: 1019 if( item ) 1020 { 1021 TearDownInterface( inMDNS, item ); 1022 } 1023 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface done (name=%s, err=%ld)\n", inAddr->ifa_name, err ); 1024 return( err ); 1025} 1026 1027//=========================================================================================================================== 1028// TearDownInterface 1029//=========================================================================================================================== 1030 1031mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem ) 1032{ 1033 MDNSSocketRef socketRef; 1034 1035 check( inMDNS ); 1036 check( inItem ); 1037 1038 // Deregister this interface with mDNS. 1039 1040 dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering IP address: %u.%u.%u.%u\n", 1041 inItem->hostSet.ip.ip.v4.b[ 0 ], inItem->hostSet.ip.ip.v4.b[ 1 ], 1042 inItem->hostSet.ip.ip.v4.b[ 2 ], inItem->hostSet.ip.ip.v4.b[ 3 ] ); 1043 1044 if( inItem->hostRegistered ) 1045 { 1046 inItem->hostRegistered = mDNSfalse; 1047 mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, mDNSfalse ); 1048 } 1049 1050 // Close the multicast socket. 1051 1052 socketRef = inItem->multicastSocketRef; 1053 inItem->multicastSocketRef = kInvalidSocketRef; 1054 if( socketRef != kInvalidSocketRef ) 1055 { 1056 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down multicast socket %d\n", socketRef ); 1057 close( socketRef ); 1058 } 1059 1060 // Close the sending socket. 1061 1062 socketRef = inItem->sendingSocketRef; 1063 inItem->sendingSocketRef = kInvalidSocketRef; 1064 if( socketRef != kInvalidSocketRef ) 1065 { 1066 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down sending socket %d\n", socketRef ); 1067 close( socketRef ); 1068 } 1069 1070 // Free the memory used by the interface info. 1071 1072 free( inItem ); 1073 return( mStatus_NoError ); 1074} 1075 1076//=========================================================================================================================== 1077// SetupSocket 1078//=========================================================================================================================== 1079 1080mDNSlocal mStatus 1081SetupSocket( 1082 mDNS * const inMDNS, 1083 const struct ifaddrs * inAddr, 1084 mDNSIPPort inPort, 1085 MDNSSocketRef * outSocketRef ) 1086{ 1087 mStatus err; 1088 MDNSSocketRef socketRef; 1089 int option; 1090 unsigned char optionByte; 1091 struct ip_mreq mreq; 1092 const struct sockaddr_in * ipv4; 1093 struct sockaddr_in addr; 1094 mDNSv4Addr ip; 1095 1096 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done\n" ); 1097 check( inMDNS ); 1098 check( inAddr ); 1099 check( inAddr->ifa_addr ); 1100 ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr; 1101 check( outSocketRef ); 1102 1103 // Set up a UDP socket for multicast DNS. 1104 1105 socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); 1106 require_errno_action( socketRef, errno, exit, err = mStatus_UnknownErr ); 1107 1108 // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving 1109 // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems 1110 // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the 1111 // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to 1112 // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122). 1113 1114 if( inPort.NotAnInteger != zeroIPPort.NotAnInteger ) 1115 { 1116 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets. 1117 1118 option = 1; 1119 err = setsockopt( socketRef, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) ); 1120 check_errno( err, errno ); 1121 1122 // Join the all-DNS multicast group so we receive Multicast DNS packets. 1123 1124 ip.NotAnInteger = ipv4->sin_addr.s_addr; 1125 mreq.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; 1126 mreq.imr_interface.s_addr = ip.NotAnInteger; 1127 err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) ); 1128 check_errno( err, errno ); 1129 1130 // Bind to the multicast DNS address and port 5353. 1131 1132 mDNSPlatformMemZero( &addr, sizeof( addr ) ); 1133 addr.sin_family = AF_INET; 1134 addr.sin_port = inPort.NotAnInteger; 1135 addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; 1136 err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) ); 1137 check_errno( err, errno ); 1138 1139 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n", 1140 inAddr->ifa_name, ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], ntohs( inPort.NotAnInteger ), socketRef ); 1141 } 1142 else 1143 { 1144 // Bind to the interface address and multicast DNS port. 1145 1146 ip.NotAnInteger = ipv4->sin_addr.s_addr; 1147 mDNSPlatformMemZero( &addr, sizeof( addr ) ); 1148 addr.sin_family = AF_INET; 1149 addr.sin_port = MulticastDNSPort.NotAnInteger; 1150 addr.sin_addr.s_addr = ip.NotAnInteger; 1151 err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) ); 1152 check_errno( err, errno ); 1153 1154 // Direct multicast packets to the specified interface. 1155 1156 addr.sin_addr.s_addr = ip.NotAnInteger; 1157 err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addr.sin_addr, sizeof( addr.sin_addr ) ); 1158 check_errno( err, errno ); 1159 1160 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing). 1161 1162 option = 255; 1163 err = setsockopt( socketRef, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) ); 1164 check_errno( err, errno ); 1165 1166 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing). 1167 1168 optionByte = 255; 1169 err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &optionByte, sizeof( optionByte ) ); 1170 check_errno( err, errno ); 1171 1172 // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are 1173 // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway. 1174 1175#if 0 1176 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate. 1177 1178 option = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; 1179 err = setsockopt( socketRef, IPPROTO_IP, IP_TOS, (char *) &option, sizeof( option ) ); 1180 check_errno( err, errno ); 1181#endif 1182 1183 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up sending socket done (%s, %u.%u.%u.%u, %d)\n", 1184 inAddr->ifa_name, ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], socketRef ); 1185 } 1186 1187 // Success! 1188 1189 *outSocketRef = socketRef; 1190 socketRef = kInvalidSocketRef; 1191 err = mStatus_NoError; 1192 1193exit: 1194 if( socketRef != kInvalidSocketRef ) 1195 { 1196 close( socketRef ); 1197 } 1198 return( err ); 1199} 1200 1201#if 0 1202#pragma mark - 1203#pragma mark == Commands == 1204#endif 1205 1206//=========================================================================================================================== 1207// SetupCommandPipe 1208//=========================================================================================================================== 1209 1210mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS ) 1211{ 1212 mStatus err; 1213 1214 // Clean up any leftover command pipe. 1215 1216 TearDownCommandPipe( inMDNS ); 1217 1218 // Create the pipe device and open it. 1219 1220 pipeDevCreate( kMDNSPipeName, kMDNSPipeMessageQueueSize, kMDNSPipeMessageSize ); 1221 1222 inMDNS->p->commandPipe = open( kMDNSPipeName, O_RDWR, 0 ); 1223 require_errno_action( inMDNS->p->commandPipe, errno, exit, err = mStatus_UnsupportedErr ); 1224 1225 err = mStatus_NoError; 1226 1227exit: 1228 return( err ); 1229} 1230 1231//=========================================================================================================================== 1232// TearDownCommandPipe 1233//=========================================================================================================================== 1234 1235mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS ) 1236{ 1237 if( inMDNS->p->commandPipe != ERROR ) 1238 { 1239 close( inMDNS->p->commandPipe ); 1240#ifdef _WRS_VXWORKS_5_X 1241 // pipeDevDelete is not defined in older versions of VxWorks 1242 pipeDevDelete( kMDNSPipeName, FALSE ); 1243#endif 1244 inMDNS->p->commandPipe = ERROR; 1245 } 1246 return( mStatus_NoError ); 1247} 1248 1249//=========================================================================================================================== 1250// SendCommand 1251//=========================================================================================================================== 1252 1253mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode ) 1254{ 1255 mStatus err; 1256 1257 require_action( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr ); 1258 1259 err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) ); 1260 require_errno( err, errno, exit ); 1261 1262 err = mStatus_NoError; 1263 1264exit: 1265 return( err ); 1266} 1267 1268//=========================================================================================================================== 1269// ProcessCommand 1270//=========================================================================================================================== 1271 1272mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS ) 1273{ 1274 mStatus err; 1275 MDNSPipeCommandCode commandCode; 1276 1277 require_action( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr ); 1278 1279 // Read the command code from the pipe and dispatch it. 1280 1281 err = read( inMDNS->p->commandPipe, &commandCode, sizeof( commandCode ) ); 1282 require_errno( err, errno, exit ); 1283 1284 switch( commandCode ) 1285 { 1286 case kMDNSPipeCommandCodeReschedule: 1287 1288 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again. 1289 1290 dlog( kDebugLevelChatty, DEBUG_NAME "reschedule\n" ); 1291 break; 1292 1293 case kMDNSPipeCommandCodeReconfigure: 1294 ProcessCommandReconfigure( inMDNS ); 1295 break; 1296 1297 case kMDNSPipeCommandCodeQuit: 1298 1299 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally. 1300 1301 dlog( kDebugLevelVerbose, DEBUG_NAME "processing pipe quit command\n" ); 1302 inMDNS->p->quit = mDNStrue; 1303 ++inMDNS->p->configID; 1304 break; 1305 1306 default: 1307 dlog( kDebugLevelError, DEBUG_NAME "unknown pipe command code (code=0x%08X)\n", commandCode ); 1308 err = mStatus_BadParamErr; 1309 goto exit; 1310 break; 1311 } 1312 err = mStatus_NoError; 1313 1314exit: 1315 return( err ); 1316} 1317 1318//=========================================================================================================================== 1319// ProcessCommandReconfigure 1320//=========================================================================================================================== 1321 1322mDNSlocal void ProcessCommandReconfigure( mDNS *inMDNS ) 1323{ 1324 mStatus err; 1325 1326 dlog( kDebugLevelVerbose, DEBUG_NAME "processing pipe reconfigure command\n" ); 1327 1328 // Tear down the existing interfaces and set up new ones using the new IP info. 1329 1330 mDNSPlatformLock( inMDNS ); 1331 1332 err = TearDownInterfaceList( inMDNS ); 1333 check_noerr( err ); 1334 1335 err = SetupInterfaceList( inMDNS ); 1336 check_noerr( err ); 1337 1338 mDNSPlatformUnlock( inMDNS ); 1339 1340 // Inform clients of the change. 1341 1342 mDNS_ConfigChanged(m); 1343 1344 // Force mDNS to update. 1345 1346 mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this 1347 1348 // Bump the config ID so the main processing loop detects the configuration change. 1349 1350 ++inMDNS->p->configID; 1351} 1352 1353#if 0 1354#pragma mark - 1355#pragma mark == Threads == 1356#endif 1357 1358//=========================================================================================================================== 1359// SetupTask 1360//=========================================================================================================================== 1361 1362mDNSlocal mStatus SetupTask( mDNS * const inMDNS ) 1363{ 1364 mStatus err; 1365 int task; 1366 1367 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread\n" ); 1368 check( inMDNS ); 1369 1370 // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the 1371 // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID. 1372 // This also means code in this thread context cannot rely on the task ID until the task has fully initialized. 1373 1374 task = taskSpawn( kMDNSTaskName, kMDNSTaskPriority, 0, kMDNSTaskStackSize, (FUNCPTR) Task, 1375 (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 1376 require_action( task != ERROR, exit, err = mStatus_NoMemoryErr ); 1377 1378 err = mStatus_NoError; 1379 1380exit: 1381 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread done (err=%ld, id=%d)\n", err, task ); 1382 return( err ); 1383} 1384 1385//=========================================================================================================================== 1386// TearDownTask 1387//=========================================================================================================================== 1388 1389mDNSlocal mStatus TearDownTask( mDNS * const inMDNS ) 1390{ 1391 mStatus err; 1392 1393 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down thread\n" ); 1394 check( inMDNS ); 1395 1396 // Send a quit command to cause the thread to exit. 1397 1398 SendCommand( inMDNS, kMDNSPipeCommandCodeQuit ); 1399 1400 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread. 1401 1402 if( inMDNS->p->quitEvent ) 1403 { 1404 err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 ); 1405 check_noerr( err ); 1406 } 1407 err = mStatus_NoError; 1408 1409 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down thread done (err=%ld)\n", err ); 1410 return( err ); 1411} 1412 1413//=========================================================================================================================== 1414// Task 1415//=========================================================================================================================== 1416 1417mDNSlocal void Task( mDNS *inMDNS ) 1418{ 1419 mStatus err; 1420 fd_set allReadSet; 1421 MDNSInterfaceItem * item; 1422 int maxSocket; 1423 long configID; 1424 struct timeval timeout; 1425 1426 dlog( kDebugLevelVerbose, DEBUG_NAME "task starting\n" ); 1427 check( inMDNS ); 1428 1429 // Set up everything up. 1430 1431 err = TaskInit( inMDNS ); 1432 require_noerr( err, exit ); 1433 1434 // Main Processing Loop. 1435 1436 while( !inMDNS->p->quit ) 1437 { 1438 // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop. 1439 // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again. 1440 1441 TaskSetupReadSet( inMDNS, &allReadSet, &maxSocket ); 1442 configID = inMDNS->p->configID; 1443 dlog( kDebugLevelVerbose, DEBUG_NAME "task starting processing loop (configID=%ld)\n", configID ); 1444 1445 while( configID == inMDNS->p->configID ) 1446 { 1447 mDNSs32 nextTaskTime; 1448 fd_set readSet; 1449 int n; 1450 1451 // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute 1452 // so anything that needs processing during or after causes a re-schedule to wake up the thread. The 1453 // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while 1454 // processing packets. This introduces a window for a race condition because the thread wake-up and 1455 // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted" 1456 // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute. 1457 1458 inMDNS->p->rescheduled = 0; 1459 nextTaskTime = mDNS_Execute( inMDNS ); 1460 TaskSetupTimeout( inMDNS, nextTaskTime, &timeout ); 1461 1462 // Wait until something occurs (e.g. command, incoming packet, or timeout). 1463 1464 readSet = allReadSet; 1465 n = select( maxSocket + 1, &readSet, NULL, NULL, &timeout ); 1466 inMDNS->p->rescheduled = 1; 1467 check_errno( n, errno ); 1468 dlog( kDebugLevelChatty - 1, DEBUG_NAME "task select result = %d\n", n ); 1469 if( n == 0 ) 1470 { 1471 // Next task timeout occurred. Loop back up to give mDNS core a chance to work. 1472 1473 dlog( kDebugLevelChatty, DEBUG_NAME "next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS) ); 1474 continue; 1475 } 1476 1477 // Scan the read set to determine if any sockets have something pending and process them. 1478 1479 n = 0; 1480 for( item = inMDNS->p->interfaceList; item; item = item->next ) 1481 { 1482 if( FD_ISSET( item->multicastSocketRef, &readSet ) ) 1483 { 1484 TaskProcessPacket( inMDNS, item, item->multicastSocketRef ); 1485 ++n; 1486 } 1487 } 1488 1489 // Check for a pending command and process it. 1490 1491 if( FD_ISSET( inMDNS->p->commandPipe, &readSet ) ) 1492 { 1493 ProcessCommand( inMDNS ); 1494 ++n; 1495 } 1496 check( n > 0 ); 1497 } 1498 } 1499 1500exit: 1501 // Signal we've quit. 1502 1503 check( inMDNS->p->quitEvent ); 1504 semGive( inMDNS->p->quitEvent ); 1505 1506 dlog( kDebugLevelInfo, DEBUG_NAME "task ended\n" ); 1507} 1508 1509//=========================================================================================================================== 1510// TaskInit 1511//=========================================================================================================================== 1512 1513mDNSlocal mStatus TaskInit( mDNS *inMDNS ) 1514{ 1515 mStatus err; 1516 1517 dlog( kDebugLevelVerbose, DEBUG_NAME "task init\n" ); 1518 check( inMDNS->p->readyEvent ); 1519 1520 inMDNS->p->task = taskIdSelf(); 1521 1522 err = SetupCommandPipe( inMDNS ); 1523 require_noerr( err, exit ); 1524 1525 SetupNames( inMDNS ); 1526 1527 err = SetupInterfaceList( inMDNS ); 1528 require_noerr( err, exit ); 1529 1530exit: 1531 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not). 1532 1533 inMDNS->p->taskInitErr = err; 1534 semGive( inMDNS->p->readyEvent ); 1535 1536 dlog( kDebugLevelVerbose, DEBUG_NAME "task init done (err=%ld)\n", err ); 1537 return( err ); 1538} 1539 1540//=========================================================================================================================== 1541// TaskSetupReadSet 1542//=========================================================================================================================== 1543 1544mDNSlocal void TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket ) 1545{ 1546 MDNSInterfaceItem * item; 1547 int maxSocket; 1548 1549 dlog( kDebugLevelVerbose, DEBUG_NAME "task setting up read set\n" ); 1550 check( inMDNS ); 1551 check( outReadSet ); 1552 check( outMaxSocket ); 1553 1554 // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This 1555 // should never happen since we should always have at least one interface, but it's just to be safe. 1556 1557 FD_ZERO( outReadSet ); 1558 maxSocket = -1; 1559 1560 // Add all the receiving sockets to the read set. 1561 1562 for( item = inMDNS->p->interfaceList; item; item = item->next ) 1563 { 1564 FD_SET( item->multicastSocketRef, outReadSet ); 1565 if( item->multicastSocketRef > maxSocket ) 1566 { 1567 maxSocket = item->multicastSocketRef; 1568 } 1569 } 1570 1571 // Add the command pipe to the read set. 1572 1573 FD_SET( inMDNS->p->commandPipe, outReadSet ); 1574 if( inMDNS->p->commandPipe > maxSocket ) 1575 { 1576 maxSocket = inMDNS->p->commandPipe; 1577 } 1578 check( maxSocket > 0 ); 1579 *outMaxSocket = maxSocket; 1580 1581 dlog( kDebugLevelVerbose, DEBUG_NAME "task setting up read set done (maxSocket=%d)\n", maxSocket ); 1582} 1583 1584//=========================================================================================================================== 1585// TaskSetupTimeout 1586//=========================================================================================================================== 1587 1588mDNSlocal void TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout ) 1589{ 1590 mDNSs32 delta; 1591 1592 // Calculate how long to wait before performing idle processing. 1593 1594 delta = inNextTaskTime - mDNS_TimeNow(inMDNS); 1595 if( delta <= 0 ) 1596 { 1597 // The next task time is now or in the past. Set the timeout to fire immediately. 1598 1599 outTimeout->tv_sec = 0; 1600 outTimeout->tv_usec = 0; 1601 } 1602 else 1603 { 1604 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder 1605 // before multiplying to account for integer rounding error and avoid firing the timeout too early. 1606 1607 outTimeout->tv_sec = delta / mDNSPlatformOneSecond; 1608 outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicrosecondsMultiplier; 1609 1610 // Check if the microseconds is more than 1 second. If so, bump the seconds instead. 1611 1612 if( outTimeout->tv_usec >= 1000000L ) 1613 { 1614 outTimeout->tv_sec += 1; 1615 outTimeout->tv_usec = 0; 1616 } 1617 } 1618 1619 dlog( kDebugLevelChatty, DEBUG_NAME "next task in %ld:%ld seconds (%ld)\n", 1620 outTimeout->tv_sec, outTimeout->tv_usec, inNextTaskTime ); 1621} 1622//=========================================================================================================================== 1623// TaskProcessPacket 1624//=========================================================================================================================== 1625 1626mDNSlocal void TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef ) 1627{ 1628 int n; 1629 DNSMessage packet; 1630 struct sockaddr_in addr; 1631 int addrSize; 1632 mDNSu8 * packetEndPtr; 1633 mDNSAddr srcAddr; 1634 mDNSIPPort srcPort; 1635 mDNSAddr dstAddr; 1636 mDNSIPPort dstPort; 1637 1638 // Receive the packet. 1639 1640 addrSize = sizeof( addr ); 1641 n = recvfrom( inSocketRef, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize ); 1642 check( n >= 0 ); 1643 if( n >= 0 ) 1644 { 1645 // Set up the src/dst/interface info. 1646 1647 srcAddr.type = mDNSAddrType_IPv4; 1648 srcAddr.ip.v4.NotAnInteger = addr.sin_addr.s_addr; 1649 srcPort.NotAnInteger = addr.sin_port; 1650 dstAddr.type = mDNSAddrType_IPv4; 1651 dstAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4; 1652 dstPort = MulticastDNSPort; 1653 1654 dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" ); 1655 dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", n ); 1656 dlog( kDebugLevelChatty, DEBUG_NAME " src = %u.%u.%u.%u:%hu\n", 1657 srcAddr.ip.v4.b[ 0 ], srcAddr.ip.v4.b[ 1 ], srcAddr.ip.v4.b[ 2 ], srcAddr.ip.v4.b[ 3 ], 1658 ntohs( srcPort.NotAnInteger ) ); 1659 dlog( kDebugLevelChatty, DEBUG_NAME " dst = %u.%u.%u.%u:%hu\n", 1660 dstAddr.ip.v4.b[ 0 ], dstAddr.ip.v4.b[ 1 ], dstAddr.ip.v4.b[ 2 ], dstAddr.ip.v4.b[ 3 ], 1661 ntohs( dstPort.NotAnInteger ) ); 1662 dlog( kDebugLevelChatty, DEBUG_NAME " interface = 0x%08X\n", (int) inItem->hostSet.InterfaceID ); 1663 dlog( kDebugLevelChatty, DEBUG_NAME "--\n" ); 1664 1665 // Dispatch the packet to mDNS. 1666 1667 packetEndPtr = ( (mDNSu8 *) &packet ) + n; 1668 mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inItem->hostSet.InterfaceID ); 1669 } 1670 1671 // Update counters. 1672 1673 inItem->recvCounter += 1; 1674 inItem->recvErrorCounter += ( n < 0 ); 1675} 1676 1677#if 0 1678#pragma mark - 1679#pragma mark == Utilities == 1680#endif 1681 1682#if ( TARGET_NON_APPLE ) 1683//=========================================================================================================================== 1684// GenerateUniqueHostName 1685// 1686// Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name. 1687//=========================================================================================================================== 1688 1689mDNSlocal void GenerateUniqueHostName( char *outName, long *ioSeed ) 1690{ 1691 DEBUG_UNUSED( ioSeed ); 1692 1693 // $$$ Non-Apple Platforms: Fill in appropriate name for device. 1694 1695 mDNSPlatformStrCopy( outName, kMDNSDefaultName ); 1696} 1697 1698//=========================================================================================================================== 1699// GenerateUniqueDNSName 1700// 1701// Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be 1702// implemented to return a unique name. 1703//=========================================================================================================================== 1704 1705mDNSlocal void GenerateUniqueDNSName( char *outName, long *ioSeed ) 1706{ 1707 DEBUG_UNUSED( ioSeed ); 1708 1709 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device. 1710 1711 mDNSPlatformStrCopy( outName, kMDNSDefaultName ); 1712} 1713#endif 1714 1715#if 0 1716#pragma mark - 1717#endif 1718 1719//=========================================================================================================================== 1720// getifaddrs 1721//=========================================================================================================================== 1722 1723int getifaddrs( struct ifaddrs **outAddrs ) 1724{ 1725 int err; 1726 struct ifaddrs * head; 1727 struct ifaddrs ** next; 1728 struct ifaddrs * ifa; 1729 int i; 1730 struct ifnet * ifp; 1731 char ipString[ INET_ADDR_LEN ]; 1732 int n; 1733 1734 head = NULL; 1735 next = &head; 1736 1737 i = 1; 1738 for( ;; ) 1739 { 1740 ifp = ifIndexToIfp( i ); 1741 if( !ifp ) 1742 { 1743 break; 1744 } 1745 ++i; 1746 1747 // Allocate and initialize the ifaddrs structure and attach it to the linked list. 1748 1749 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) ); 1750 require_action( ifa, exit, err = ENOMEM ); 1751 1752 *next = ifa; 1753 next = &ifa->ifa_next; 1754 1755 // Fetch the name. 1756 1757 ifa->ifa_name = (char *) malloc( 16 ); 1758 require_action( ifa->ifa_name, exit, err = ENOMEM ); 1759 1760 n = sprintf( ifa->ifa_name, "%s%d", ifp->if_name, ifp->if_unit ); 1761 require_action( n < 16, exit, err = ENOBUFS ); 1762 1763 // Fetch the address. 1764 1765 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( struct sockaddr_in ) ); 1766 require_action( ifa->ifa_addr, exit, err = ENOMEM ); 1767 1768 ipString[ 0 ] = '\0'; 1769 #if ( TARGET_NON_APPLE ) 1770 err = ifAddrGet( ifa->ifa_name, ipString ); 1771 require_noerr( err, exit ); 1772 #else 1773 err = ifAddrGetNonAlias( ifa->ifa_name, ipString ); 1774 require_noerr( err, exit ); 1775 #endif 1776 1777 err = sock_pton( ipString, AF_INET, ifa->ifa_addr, 0, NULL ); 1778 require_noerr( err, exit ); 1779 1780 // Fetch flags. 1781 1782 ifa->ifa_flags = ifp->if_flags; 1783 } 1784 1785 // Success! 1786 1787 if( outAddrs ) 1788 { 1789 *outAddrs = head; 1790 head = NULL; 1791 } 1792 err = 0; 1793 1794exit: 1795 if( head ) 1796 { 1797 freeifaddrs( head ); 1798 } 1799 return( err ); 1800} 1801 1802//=========================================================================================================================== 1803// freeifaddrs 1804//=========================================================================================================================== 1805 1806void freeifaddrs( struct ifaddrs *inAddrs ) 1807{ 1808 struct ifaddrs * p; 1809 struct ifaddrs * q; 1810 1811 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields. 1812 1813 for( p = inAddrs; p; p = q ) 1814 { 1815 q = p->ifa_next; 1816 1817 if( p->ifa_name ) 1818 { 1819 free( p->ifa_name ); 1820 p->ifa_name = NULL; 1821 } 1822 if( p->ifa_addr ) 1823 { 1824 free( p->ifa_addr ); 1825 p->ifa_addr = NULL; 1826 } 1827 if( p->ifa_netmask ) 1828 { 1829 free( p->ifa_netmask ); 1830 p->ifa_netmask = NULL; 1831 } 1832 if( p->ifa_dstaddr ) 1833 { 1834 free( p->ifa_dstaddr ); 1835 p->ifa_dstaddr = NULL; 1836 } 1837 if( p->ifa_data ) 1838 { 1839 free( p->ifa_data ); 1840 p->ifa_data = NULL; 1841 } 1842 free( p ); 1843 } 1844} 1845 1846//=========================================================================================================================== 1847// sock_pton 1848//=========================================================================================================================== 1849 1850int sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize ) 1851{ 1852 int err; 1853 1854 if( inFamily == AF_INET ) 1855 { 1856 struct sockaddr_in * ipv4; 1857 1858 if( inAddrSize == 0 ) 1859 { 1860 inAddrSize = sizeof( struct sockaddr_in ); 1861 } 1862 if( inAddrSize < sizeof( struct sockaddr_in ) ) 1863 { 1864 err = EINVAL; 1865 goto exit; 1866 } 1867 1868 ipv4 = (struct sockaddr_in *) outAddr; 1869 err = inet_aton( (char *) inString, &ipv4->sin_addr ); 1870 if( err == 0 ) 1871 { 1872 ipv4->sin_family = AF_INET; 1873 if( outAddrSize ) 1874 { 1875 *outAddrSize = sizeof( struct sockaddr_in ); 1876 } 1877 } 1878 } 1879#if ( defined( AF_INET6 ) ) 1880 else if( inFamily == AF_INET6 ) // $$$ TO DO: Add IPv6 support. 1881 { 1882 err = EAFNOSUPPORT; 1883 goto exit; 1884 } 1885#endif 1886 else 1887 { 1888 err = EAFNOSUPPORT; 1889 goto exit; 1890 } 1891 1892exit: 1893 return( err ); 1894} 1895 1896//=========================================================================================================================== 1897// sock_ntop 1898//=========================================================================================================================== 1899 1900char * sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize ) 1901{ 1902 const struct sockaddr * addr; 1903 1904 addr = (const struct sockaddr *) inAddr; 1905 if( addr->sa_family == AF_INET ) 1906 { 1907 struct sockaddr_in * ipv4; 1908 1909 if( inAddrSize == 0 ) 1910 { 1911 inAddrSize = sizeof( struct sockaddr_in ); 1912 } 1913 if( inAddrSize < sizeof( struct sockaddr_in ) ) 1914 { 1915 errno = EINVAL; 1916 inBuffer = NULL; 1917 goto exit; 1918 } 1919 if( inBufferSize < 16 ) 1920 { 1921 errno = ENOBUFS; 1922 inBuffer = NULL; 1923 goto exit; 1924 } 1925 1926 ipv4 = (struct sockaddr_in *) addr; 1927 inet_ntoa_b( ipv4->sin_addr, inBuffer ); 1928 } 1929#if ( defined( AF_INET6 ) ) 1930 else if( addr->sa_family == AF_INET6 ) // $$$ TO DO: Add IPv6 support. 1931 { 1932 errno = EAFNOSUPPORT; 1933 inBuffer = NULL; 1934 goto exit; 1935 } 1936#endif 1937 else 1938 { 1939 errno = EAFNOSUPPORT; 1940 inBuffer = NULL; 1941 goto exit; 1942 } 1943 1944exit: 1945 return( inBuffer ); 1946} 1947 1948#if 0 1949#pragma mark - 1950#pragma mark == Debugging == 1951#endif 1952 1953#if ( DEBUG ) 1954 1955void mDNSShow( BOOL inShowRecords ); 1956void mDNSShowRecords( void ); 1957void mDNSShowTXT( const void *inTXT, size_t inTXTSize ); 1958 1959//=========================================================================================================================== 1960// mDNSShow 1961//=========================================================================================================================== 1962 1963void mDNSShow( BOOL inShowRecords ) 1964{ 1965 MDNSInterfaceItem * item; 1966 mDNSAddr ip; 1967 int n; 1968 1969 if( !gMDNSPtr ) 1970 { 1971 printf( "### mDNS not initialized\n" ); 1972 return; 1973 } 1974 1975 // Globals 1976 1977 printf( "\n-- mDNS globals --\n" ); 1978 printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS ) ); 1979 printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord ) ); 1980 printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord ) ); 1981 printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord ) ); 1982 printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr ); 1983 printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier ); 1984 printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr->p->lockID ); 1985 printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr->p->readyEvent ); 1986 printf( " taskInitErr = %ld\n", gMDNSPtr->p->taskInitErr ); 1987 printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr->p->quitEvent ); 1988 printf( " commandPipe = %d\n", gMDNSPtr->p->commandPipe ); 1989 printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr->p->task ); 1990 printf( " quit = %d\n", gMDNSPtr->p->quit ); 1991 printf( " configID = %ld\n", gMDNSPtr->p->configID ); 1992 printf( " rescheduled = %d\n", gMDNSPtr->p->rescheduled ); 1993 printf( " nicelabel = \"%.*s\"\n", gMDNSPtr->nicelabel.c[ 0 ], (char *) &gMDNSPtr->nicelabel.c[ 1 ] ); 1994 printf( " hostLabel = \"%.*s\"\n", gMDNSPtr->hostlabel.c[ 0 ], (char *) &gMDNSPtr->hostlabel.c[ 1 ] ); 1995 printf( "\n"); 1996 1997 // Interfaces 1998 1999 printf( "\n-- mDNS interfaces --\n" ); 2000 n = 1; 2001 for( item = gMDNSPtr->p->interfaceList; item; item = item->next ) 2002 { 2003 printf( " -- interface %u --\n", n ); 2004 printf( " name = \"%s\"\n", item->name ); 2005 printf( " multicastSocketRef = %d\n", item->multicastSocketRef ); 2006 printf( " sendingSocketRef = %d\n", item->sendingSocketRef ); 2007 ip = item->hostSet.ip; 2008 printf( " hostSet.ip = %u.%u.%u.%u\n", ip.ip.v4.b[ 0 ], ip.ip.v4.b[ 1 ], 2009 ip.ip.v4.b[ 2 ], ip.ip.v4.b[ 3 ] ); 2010 printf( " hostSet.advertise = %s\n", item->hostSet.Advertise ? "YES" : "NO" ); 2011 printf( " hostRegistered = %s\n", item->hostRegistered ? "YES" : "NO" ); 2012 printf( " --\n" ); 2013 printf( " sendMulticastCounter = %d\n", item->sendMulticastCounter ); 2014 printf( " sendUnicastCounter = %d\n", item->sendUnicastCounter ); 2015 printf( " sendErrorCounter = %d\n", item->sendErrorCounter ); 2016 printf( " recvCounter = %d\n", item->recvCounter ); 2017 printf( " recvErrorCounter = %d\n", item->recvErrorCounter ); 2018 printf( " recvLoopCounter = %d\n", item->recvLoopCounter ); 2019 printf( "\n" ); 2020 ++n; 2021 } 2022 2023 // Resource Records 2024 2025 if( inShowRecords ) 2026 { 2027 mDNSShowRecords(); 2028 } 2029} 2030 2031//=========================================================================================================================== 2032// mDNSShowRecords 2033//=========================================================================================================================== 2034 2035void mDNSShowRecords( void ) 2036{ 2037 MDNSInterfaceItem * item; 2038 int n; 2039 AuthRecord * record; 2040 char name[ MAX_ESCAPED_DOMAIN_NAME ]; 2041 2042 printf( "\n-- mDNS resource records --\n" ); 2043 n = 1; 2044 for( record = gMDNSPtr->ResourceRecords; record; record = record->next ) 2045 { 2046 item = (MDNSInterfaceItem *) record->resrec.InterfaceID; 2047 ConvertDomainNameToCString( &record->resrec.name, name ); 2048 printf( " -- record %d --\n", n ); 2049 printf( " interface = 0x%08X (%s)\n", (int) item, item ? item->name : "<any>" ); 2050 printf( " name = \"%s\"\n", name ); 2051 printf( "\n" ); 2052 ++n; 2053 } 2054 printf( "\n"); 2055} 2056 2057//=========================================================================================================================== 2058// mDNSShowTXT 2059//=========================================================================================================================== 2060 2061void mDNSShowTXT( const void *inTXT, size_t inTXTSize ) 2062{ 2063 const mDNSu8 * p; 2064 const mDNSu8 * end; 2065 int i; 2066 mDNSu8 size; 2067 2068 printf( "\nTXT record (%u bytes):\n\n", inTXTSize ); 2069 2070 p = (const mDNSu8 *) inTXT; 2071 end = p + inTXTSize; 2072 i = 0; 2073 2074 while( p < end ) 2075 { 2076 size = *p++; 2077 if( ( p + size ) > end ) 2078 { 2079 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" ); 2080 break; 2081 } 2082 printf( "%2d (%3d bytes): \"%.*s\"\n", i, size, size, p ); 2083 p += size; 2084 ++i; 2085 } 2086 printf( "\n" ); 2087} 2088#endif // DEBUG 2089