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