Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSVxWorks / mDNSVxWorksIPv4Only.c
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 )
84 debug_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
109 typedef uint8_t MDNSPipeCommandCode;
110 enum
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
126 typedef int MDNSSocketRef;
127
128 struct  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
192 extern struct ifnet * ifIndexToIfp(int ifIndex);
193
194 // Platform Internals
195
196 mDNSlocal void      SetupNames( mDNS * const inMDNS );
197 mDNSlocal mStatus   SetupInterfaceList( mDNS * const inMDNS );
198 mDNSlocal mStatus   TearDownInterfaceList( mDNS * const inMDNS );
199 mDNSlocal mStatus   SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem );
200 mDNSlocal mStatus   TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem );
201 mDNSlocal mStatus
202 SetupSocket(
203     mDNS * const inMDNS,
204     const struct ifaddrs *  inAddr,
205     mDNSIPPort inPort,
206     MDNSSocketRef *         outSocketRef );
207
208 // Commands
209
210 mDNSlocal mStatus   SetupCommandPipe( mDNS * const inMDNS );
211 mDNSlocal mStatus   TearDownCommandPipe( mDNS * const inMDNS );
212 mDNSlocal mStatus   SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
213 mDNSlocal mStatus   ProcessCommand( mDNS * const inMDNS );
214 mDNSlocal void      ProcessCommandReconfigure( mDNS *inMDNS );
215
216 // Threads
217
218 mDNSlocal mStatus   SetupTask( mDNS * const inMDNS );
219 mDNSlocal mStatus   TearDownTask( mDNS * const inMDNS );
220 mDNSlocal void      Task( mDNS *inMDNS );
221 mDNSlocal mStatus   TaskInit( mDNS *inMDNS );
222 mDNSlocal void      TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket );
223 mDNSlocal void      TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout );
224 mDNSlocal void      TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef );
225
226 // Utilities
227
228 #if ( TARGET_NON_APPLE )
229 mDNSlocal void  GenerateUniqueHostName( char *outName, long *ioSeed );
230 mDNSlocal void  GenerateUniqueDNSName( char *outName, long *ioSeed );
231 #endif
232
233 // Platform Accessors
234
235 #ifdef  __cplusplus
236 extern "C" {
237 #endif
238
239 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
240 struct  mDNSPlatformInterfaceInfo
241 {
242     const char *        name;
243     mDNSAddr ip;
244 };
245
246 mDNSexport mStatus  mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
247 mDNSexport 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
261 mDNSlocal mDNS *                    gMDNSPtr                            = NULL;
262 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
263 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier  = 0;
264
265 // Platform support
266
267 mDNSs32 mDNSPlatformOneSecond;
268
269 #if 0
270 #pragma mark -
271 #pragma mark == Public APIs ==
272 #endif
273
274 //===========================================================================================================================
275 //      mDNSReconfigure
276 //===========================================================================================================================
277
278 void    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
297 mStatus 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
339 exit:
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
352 void    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
397 mStatus
398 mDNSPlatformSendUDP(
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
462 exit:
463     dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP done\n" );
464     return( err );
465 }
466
467 //===========================================================================================================================
468 //      Connection-oriented (TCP) functions
469 //===========================================================================================================================
470
471 mDNSexport 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
483 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
484 {
485     (void)sd;           // Unused
486 }
487
488 mDNSexport 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
496 mDNSexport 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
508 void    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
526 void    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
559 mDNSu32  mDNSPlatformStrLen( const void *inSrc )
560 {
561     check( inSrc );
562
563     return( (mDNSu32) strlen( (const char *) inSrc ) );
564 }
565
566 //===========================================================================================================================
567 //      mDNSPlatformStrCopy
568 //===========================================================================================================================
569
570 void    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
582 void    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
594 mDNSBool    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
606 void    mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
607 {
608     check( inDst );
609
610     memset( inDst, 0, inSize );
611 }
612
613 //===========================================================================================================================
614 //      mDNSPlatformMemAllocate
615 //===========================================================================================================================
616
617 mDNSexport 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
633 mDNSexport void mDNSPlatformMemFree( void *inMem )
634 {
635     check( inMem );
636
637     free( inMem );
638 }
639
640 //===========================================================================================================================
641 //      mDNSPlatformRandomSeed
642 //===========================================================================================================================
643
644 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
645 {
646     return( tickGet() );
647 }
648
649 //===========================================================================================================================
650 //      mDNSPlatformTimeInit
651 //===========================================================================================================================
652
653 mDNSexport 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
663 mDNSs32 mDNSPlatformRawTime( void )
664 {
665     return( (mDNSs32) tickGet() );
666 }
667
668 //===========================================================================================================================
669 //      mDNSPlatformUTC
670 //===========================================================================================================================
671
672 mDNSexport mDNSs32  mDNSPlatformUTC( void )
673 {
674     return( -1 );
675 }
676
677 //===========================================================================================================================
678 //      mDNSPlatformInterfaceNameToID
679 //===========================================================================================================================
680
681 mStatus 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
713 exit:
714     return( err );
715 }
716
717 //===========================================================================================================================
718 //      mDNSPlatformInterfaceIDToInfo
719 //===========================================================================================================================
720
721 mStatus 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
751 exit:
752     return( err );
753 }
754
755 //===========================================================================================================================
756 //      debugf_
757 //===========================================================================================================================
758
759 #if ( MDNS_DEBUGMSGS )
760 mDNSexport 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 )
779 mDNSexport 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
797 void 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
819 mDNSlocal 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
875 mDNSlocal 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
917 exit:
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
934 mDNSlocal 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
959 mDNSlocal 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, NormalActivation );
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
1018 exit:
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
1031 mDNSlocal 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, NormalActivation );
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
1080 mDNSlocal mStatus
1081 SetupSocket(
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
1193 exit:
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
1210 mDNSlocal 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
1227 exit:
1228     return( err );
1229 }
1230
1231 //===========================================================================================================================
1232 //      TearDownCommandPipe
1233 //===========================================================================================================================
1234
1235 mDNSlocal 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
1253 mDNSlocal 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
1264 exit:
1265     return( err );
1266 }
1267
1268 //===========================================================================================================================
1269 //      ProcessCommand
1270 //===========================================================================================================================
1271
1272 mDNSlocal 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
1314 exit:
1315     return( err );
1316 }
1317
1318 //===========================================================================================================================
1319 //      ProcessCommandReconfigure
1320 //===========================================================================================================================
1321
1322 mDNSlocal 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
1362 mDNSlocal 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
1380 exit:
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
1389 mDNSlocal 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
1417 mDNSlocal 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
1500 exit:
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
1513 mDNSlocal 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
1530 exit:
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
1544 mDNSlocal 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
1588 mDNSlocal 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
1626 mDNSlocal 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
1689 mDNSlocal 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
1705 mDNSlocal 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
1723 int 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
1794 exit:
1795     if( head )
1796     {
1797         freeifaddrs( head );
1798     }
1799     return( err );
1800 }
1801
1802 //===========================================================================================================================
1803 //      freeifaddrs
1804 //===========================================================================================================================
1805
1806 void    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
1850 int 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
1892 exit:
1893     return( err );
1894 }
1895
1896 //===========================================================================================================================
1897 //      sock_ntop
1898 //===========================================================================================================================
1899
1900 char *  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
1944 exit:
1945     return( inBuffer );
1946 }
1947
1948 #if 0
1949 #pragma mark -
1950 #pragma mark == Debugging ==
1951 #endif
1952
1953 #if ( DEBUG )
1954
1955 void    mDNSShow( BOOL inShowRecords );
1956 void    mDNSShowRecords( void );
1957 void    mDNSShowTXT( const void *inTXT, size_t inTXTSize );
1958
1959 //===========================================================================================================================
1960 //      mDNSShow
1961 //===========================================================================================================================
1962
1963 void    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
2035 void    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
2061 void    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