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