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