2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 Contains: mDNS platform plugin for VxWorks.
25 Copyright: Copyright (C) 2002-2003 Apple Computer, Inc., All Rights Reserved.
27 Change History (most recent first):
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.
33 Revision 1.6 2003/08/18 23:19:05 cheshire
34 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
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.
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
42 Revision 1.3 2003/08/12 19:56:27 cheshire
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
49 Revision 1.1 2003/08/02 10:06:48 bradley
50 mDNS platform plugin for VxWorks.
53 Notes for non-Apple platforms:
55 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
59 - Add support for IPv6 (needs VxWorks IPv6 support).
62 // Set up the debug library to use the default category (see DebugServicesLite.h for details).
64 #if( !TARGET_NON_APPLE )
65 #define DEBUG_USE_DEFAULT_CATEGORY 1
74 #include <sys/types.h>
75 #include <arpa/inet.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>
88 #include "selectLib.h"
97 #if( !TARGET_NON_APPLE )
98 #include "ACP/ACPUtilities.h"
99 #include "Support/DebugServicesLite.h"
100 #include "Support/MiscUtilities.h"
103 #include "mDNSClientAPI.h"
104 #include "mDNSPlatformFunctions.h"
106 #include "mDNSVxWorks.h"
109 #pragma mark == Preprocessor ==
112 //===========================================================================================================================
114 //===========================================================================================================================
116 #if( !TARGET_NON_APPLE )
117 debug_log_new_default_category( mdns
);
121 #pragma mark == Constants ==
124 //===========================================================================================================================
126 //===========================================================================================================================
128 #define DEBUG_NAME "[mDNS] "
130 #define kMDNSDefaultName "My-Device"
132 #define kMDNSTaskName "tMDNS"
133 #define kMDNSTaskPriority 102
134 #define kMDNSTaskStackSize 49152
136 #define kMDNSPipeName "/pipe/mDNS"
137 #define kMDNSPipeMessageQueueSize 32
138 #define kMDNSPipeMessageSize 1
140 #define kInvalidSocketRef -1
142 typedef uint8_t MDNSPipeCommandCode
;
145 kMDNSPipeCommandCodeInvalid
= 0,
146 kMDNSPipeCommandCodeReschedule
= 1,
147 kMDNSPipeCommandCodeReconfigure
= 2,
148 kMDNSPipeCommandCodeQuit
= 3
152 #pragma mark == Structures ==
155 //===========================================================================================================================
157 //===========================================================================================================================
159 typedef int MDNSSocketRef
;
161 struct MDNSInterfaceItem
163 MDNSInterfaceItem
* next
;
165 MDNSSocketRef multicastSocketRef
;
166 MDNSSocketRef unicastSocketRef
;
167 MDNSSocketRef sendingSocketRef
;
168 NetworkInterfaceInfo hostSet
;
169 mDNSBool hostRegistered
;
171 int sendMulticastCounter
;
172 int sendUnicastCounter
;
173 int sendErrorCounter
;
175 int recvMulticastCounter
;
176 int recvUnicastCounter
;
177 int recvErrorCounter
;
182 #pragma mark == Macros ==
185 //===========================================================================================================================
187 //===========================================================================================================================
189 #if( TARGET_NON_APPLE )
191 // Do-nothing versions of the debugging macros for non-Apple platforms.
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)
212 #define dlog( ARGS... )
214 #define DEBUG_UNUSED( X ) (void)( X )
218 #pragma mark == Prototypes ==
221 //===========================================================================================================================
223 //===========================================================================================================================
225 // ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
227 extern struct ifnet
* ifIndexToIfp(int ifIndex
);
229 // Platform Internals
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
);
239 const struct ifaddrs
* inAddr
,
241 MDNSSocketRef
* outSocketRef
);
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
);
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
);
263 #if( TARGET_NON_APPLE )
264 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
);
265 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
);
268 // Platform Accessors
274 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
275 struct mDNSPlatformInterfaceInfo
281 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
282 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
289 #pragma mark == Globals ==
292 //===========================================================================================================================
294 //===========================================================================================================================
296 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
297 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
298 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier
= 0;
302 mDNSs32 mDNSPlatformOneSecond
;
306 #pragma mark == Public APIs ==
309 //===========================================================================================================================
311 //===========================================================================================================================
313 void mDNSReconfigure( void )
315 // Send a "reconfigure" command to the MDNS task.
319 SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
325 #pragma mark == Platform Support ==
328 //===========================================================================================================================
330 //===========================================================================================================================
332 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
336 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init\n" );
338 // Initialize variables.
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
);
348 // Allocate semaphores.
350 inMDNS
->p
->lockID
= semMCreate( SEM_Q_FIFO
);
351 require_action( inMDNS
->p
->lockID
, exit
, err
= mStatus_NoMemoryErr
);
353 inMDNS
->p
->readyEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
354 require_action( inMDNS
->p
->readyEvent
, exit
, err
= mStatus_NoMemoryErr
);
356 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
357 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
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.
364 err
= SetupTask( inMDNS
);
365 require_noerr( err
, exit
);
367 err
= semTake( inMDNS
->p
->readyEvent
, WAIT_FOREVER
);
368 require_noerr( err
, exit
);
369 err
= inMDNS
->p
->taskInitErr
;
370 require_noerr( err
, exit
);
372 mDNSCoreInitComplete( inMDNS
, err
);
377 mDNSPlatformClose( inMDNS
);
379 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
383 //===========================================================================================================================
385 //===========================================================================================================================
387 void mDNSPlatformClose( mDNS
* const inMDNS
)
391 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close\n" );
394 // Tear everything down.
396 err
= TearDownTask( inMDNS
);
399 err
= TearDownInterfaceList( inMDNS
);
402 err
= TearDownCommandPipe( inMDNS
);
407 // Release semaphores.
409 if( inMDNS
->p
->quitEvent
)
411 semDelete( inMDNS
->p
->quitEvent
);
412 inMDNS
->p
->quitEvent
= 0;
414 if( inMDNS
->p
->readyEvent
)
416 semDelete( inMDNS
->p
->readyEvent
);
417 inMDNS
->p
->readyEvent
= 0;
419 if( inMDNS
->p
->lockID
)
421 semDelete( inMDNS
->p
->lockID
);
422 inMDNS
->p
->lockID
= 0;
425 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close done\n" );
428 //===========================================================================================================================
429 // mDNSPlatformSendUDP
430 //===========================================================================================================================
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
)
443 MDNSInterfaceItem
* item
;
444 struct sockaddr_in addr
;
447 DEBUG_UNUSED( inSrcPort
);
449 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
456 check( inInterfaceID
);
458 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
460 err
= mStatus_BadParamErr
;
465 // Make sure the InterfaceID is valid.
467 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
469 if( item
== (MDNSInterfaceItem
*) inInterfaceID
)
474 require_action( item
, exit
, err
= mStatus_NoSuchNameErr
);
479 item
= (MDNSInterfaceItem
*) inInterfaceID
;
480 check( item
->sendingSocketRef
!= kInvalidSocketRef
);
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
;
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
);
491 item
->sendErrorCounter
+= ( n
< 0 );
492 item
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
493 item
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
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
;
501 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
505 //===========================================================================================================================
507 //===========================================================================================================================
509 void mDNSPlatformLock( const mDNS
* const inMDNS
)
511 check( inMDNS
->p
->lockID
);
513 if( inMDNS
->p
->lockID
)
515 #if( TARGET_NON_APPLE )
516 semTake( inMDNS
->p
->lockID
, WAIT_FOREVER
);
518 semTakeDeadlockDetect( inMDNS
->p
->lockID
, WAIT_FOREVER
);
523 //===========================================================================================================================
524 // mDNSPlatformUnlock
525 //===========================================================================================================================
527 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
531 check( inMDNS
->p
->lockID
);
532 check_string( inMDNS
->p
->task
!= ERROR
, "mDNS task not started" );
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
539 if( ( mDNSPlatformTimeNow() - inMDNS
->NextScheduledEvent
) >= 0 )
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.
544 if( ( inMDNS
->p
->rescheduled
++ == 0 ) && ( taskIdSelf() != inMDNS
->p
->task
) )
546 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
550 if( inMDNS
->p
->lockID
)
552 semGive( inMDNS
->p
->lockID
);
556 //===========================================================================================================================
557 // mDNSPlatformStrLen
558 //===========================================================================================================================
560 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
564 return( (mDNSu32
) strlen( (const char *) inSrc
) );
567 //===========================================================================================================================
568 // mDNSPlatformStrCopy
569 //===========================================================================================================================
571 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
576 strcpy( (char *) inDst
, (const char*) inSrc
);
579 //===========================================================================================================================
580 // mDNSPlatformMemCopy
581 //===========================================================================================================================
583 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
588 memcpy( inDst
, inSrc
, inSize
);
591 //===========================================================================================================================
592 // mDNSPlatformMemSame
593 //===========================================================================================================================
595 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
600 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
603 //===========================================================================================================================
604 // mDNSPlatformMemZero
605 //===========================================================================================================================
607 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
611 memset( inDst
, 0, inSize
);
614 //===========================================================================================================================
615 // mDNSPlatformMemAllocate
616 //===========================================================================================================================
618 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
624 mem
= malloc( inSize
);
630 //===========================================================================================================================
631 // mDNSPlatformMemFree
632 //===========================================================================================================================
634 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
641 //===========================================================================================================================
642 // mDNSPlatformTimeInit
643 //===========================================================================================================================
645 mDNSexport mStatus
mDNSPlatformTimeInit( mDNSs32
*outTimeNow
)
649 // No special setup is required on VxWorks -- we just use tickGet().
651 *outTimeNow
= mDNSPlatformTimeNow();
652 return( mStatus_NoError
);
655 //===========================================================================================================================
656 // mDNSPlatformTimeNow
657 //===========================================================================================================================
659 mDNSs32
mDNSPlatformTimeNow( void )
661 return( (mDNSs32
) tickGet() );
664 //===========================================================================================================================
665 // mDNSPlatformInterfaceNameToID
666 //===========================================================================================================================
668 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
671 MDNSInterfaceItem
* ifd
;
677 // Search for an interface with the specified name,
679 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
681 if( strcmp( ifd
->name
, inName
) == 0 )
688 err
= mStatus_NoSuchNameErr
;
696 *outID
= (mDNSInterfaceID
) ifd
;
698 err
= mStatus_NoError
;
704 //===========================================================================================================================
705 // mDNSPlatformInterfaceIDToInfo
706 //===========================================================================================================================
708 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
711 MDNSInterfaceItem
* ifd
;
717 // Search for an interface with the specified ID,
719 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
721 if( ifd
== (MDNSInterfaceItem
*) inID
)
728 err
= mStatus_NoSuchNameErr
;
734 outInfo
->name
= ifd
->name
;
735 outInfo
->ip
= ifd
->hostSet
.ip
;
736 err
= mStatus_NoError
;
742 //===========================================================================================================================
744 //===========================================================================================================================
746 #if( MDNS_DEBUGMSGS )
747 mDNSexport
void debugf_( const char *format
, ... )
753 va_start( args
, format
);
754 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
757 dlog( kDebugLevelInfo
, "%s\n", buffer
);
761 //===========================================================================================================================
763 //===========================================================================================================================
765 #if( MDNS_DEBUGMSGS > 1 )
766 mDNSexport
void verbosedebugf_( const char *format
, ... )
772 va_start( args
, format
);
773 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
776 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
780 //===========================================================================================================================
782 //===========================================================================================================================
784 void LogMsg( const char *inFormat
, ... )
790 va_start( args
, inFormat
);
791 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
794 dlog( kDebugLevelWarning
, "%s\n", buffer
);
799 #pragma mark == Platform Internals ==
802 //===========================================================================================================================
804 //===========================================================================================================================
806 mDNSlocal
void SetupNames( mDNS
* const inMDNS
)
808 char tempCString
[ 128 ];
809 mDNSu8 tempPString
[ 128 ];
812 // Set up the host name.
814 tempCString
[ 0 ] = '\0';
815 GenerateUniqueHostName( tempCString
, NULL
);
816 check( tempCString
[ 0 ] != '\0' );
817 if( tempCString
[ 0 ] == '\0' )
819 // No name so use the default.
821 strcpy( tempCString
, kMDNSDefaultName
);
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 );
827 // Set up the DNS name.
829 tempCString
[ 0 ] = '\0';
830 GenerateUniqueDNSName( tempCString
, NULL
);
831 if( tempCString
[ 0 ] != '\0' )
833 tempPString
[ 0 ] = strlen( tempCString
);
834 memcpy( &tempPString
[ 1 ], tempCString
, tempPString
[ 0 ] );
835 namePtr
= tempPString
;
839 // No DNS name so use the host name.
841 namePtr
= inMDNS
->nicelabel
.c
;
843 ConvertUTF8PstringToRFC1034HostLabel( namePtr
, &inMDNS
->hostlabel
);
844 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
846 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
848 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
850 check( inMDNS
->hostlabel
.c
[ 0 ] > 0 );
852 mDNS_GenerateFQDN( inMDNS
);
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 ] );
858 //===========================================================================================================================
859 // SetupInterfaceList
860 //===========================================================================================================================
862 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
865 struct ifaddrs
* addrs
;
869 MDNSInterfaceItem
** next
;
870 MDNSInterfaceItem
* item
;
874 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
877 // Tear down any existing interfaces that may be set up.
879 TearDownInterfaceList( inMDNS
);
880 inMDNS
->p
->interfaceList
= NULL
;
881 next
= &inMDNS
->p
->interfaceList
;
883 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
885 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTOPOINT
;
886 flagTest
= IFF_UP
| IFF_MULTICAST
;
888 err
= getifaddrs( &addrs
);
889 require_noerr( err
, exit
);
891 for( p
= addrs
; p
; p
= p
->ifa_next
)
893 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
895 err
= SetupInterface( inMDNS
, p
, &item
);
896 require_noerr( err
, exit
);
902 err
= mStatus_NoError
;
907 freeifaddrs( addrs
);
911 TearDownInterfaceList( inMDNS
);
913 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
917 //===========================================================================================================================
918 // TearDownInterfaceList
919 //===========================================================================================================================
921 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
923 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
926 // Tear down all the interfaces.
928 while( inMDNS
->p
->interfaceList
)
930 MDNSInterfaceItem
* item
;
932 item
= inMDNS
->p
->interfaceList
;
933 inMDNS
->p
->interfaceList
= item
->next
;
935 TearDownInterface( inMDNS
, item
);
938 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
939 return( mStatus_NoError
);
942 //===========================================================================================================================
944 //===========================================================================================================================
946 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
)
949 MDNSInterfaceItem
* item
;
950 MDNSSocketRef socketRef
;
951 const struct sockaddr_in
* ipv4
;
953 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface (name=%s)\n", inAddr
->ifa_name
);
956 check( inAddr
->ifa_addr
);
957 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
960 // Allocate memory for the info item.
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
;
969 // Set up the multicast DNS (port 5353) socket for this interface.
971 err
= SetupSocket( inMDNS
, inAddr
, MulticastDNSPort
, &socketRef
);
972 require_noerr( err
, exit
);
973 item
->multicastSocketRef
= socketRef
;
975 // Set up the unicast DNS (port 53) socket for this interface (to handle normal DNS requests).
977 err
= SetupSocket( inMDNS
, inAddr
, UnicastDNSPort
, &socketRef
);
978 require_noerr( err
, exit
);
979 item
->unicastSocketRef
= socketRef
;
981 // Set up the sending socket for this interface.
983 err
= SetupSocket( inMDNS
, inAddr
, zeroIPPort
, &socketRef
);
984 require_noerr( err
, exit
);
985 item
->sendingSocketRef
= socketRef
;
987 // Register this interface with mDNS.
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
;
994 err
= mDNS_RegisterInterface( inMDNS
, &item
->hostSet
);
995 require_noerr( err
, exit
);
996 item
->hostRegistered
= mDNStrue
;
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 ] );
1010 TearDownInterface( inMDNS
, item
);
1012 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (name=%s, err=%ld)\n", inAddr
->ifa_name
, err
);
1016 //===========================================================================================================================
1017 // TearDownInterface
1018 //===========================================================================================================================
1020 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
)
1022 MDNSSocketRef socketRef
;
1027 // Deregister this interface with mDNS.
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 ] );
1033 if( inItem
->hostRegistered
)
1035 inItem
->hostRegistered
= mDNSfalse
;
1036 mDNS_DeregisterInterface( inMDNS
, &inItem
->hostSet
);
1039 // Close the multicast socket.
1041 socketRef
= inItem
->multicastSocketRef
;
1042 inItem
->multicastSocketRef
= kInvalidSocketRef
;
1043 if( socketRef
!= kInvalidSocketRef
)
1045 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1049 // Close the unicast socket.
1051 socketRef
= inItem
->unicastSocketRef
;
1052 inItem
->unicastSocketRef
= kInvalidSocketRef
;
1053 if( socketRef
!= kInvalidSocketRef
)
1055 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down unicast socket %d\n", socketRef
);
1059 // Close the sending socket.
1061 socketRef
= inItem
->sendingSocketRef
;
1062 inItem
->sendingSocketRef
= kInvalidSocketRef
;
1063 if( socketRef
!= kInvalidSocketRef
)
1065 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down sending socket %d\n", socketRef
);
1069 // Free the memory used by the interface info.
1072 return( mStatus_NoError
);
1075 //===========================================================================================================================
1077 //===========================================================================================================================
1081 mDNS
* const inMDNS
,
1082 const struct ifaddrs
* inAddr
,
1084 MDNSSocketRef
* outSocketRef
)
1087 MDNSSocketRef socketRef
;
1089 unsigned char optionByte
;
1090 struct ip_mreq mreq
;
1091 const struct sockaddr_in
* ipv4
;
1092 struct sockaddr_in addr
;
1095 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1098 check( inAddr
->ifa_addr
);
1099 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1100 check( outSocketRef
);
1102 // Set up a UDP socket for multicast DNS.
1104 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1105 require_errno_action( socketRef
, errno
, exit
, err
= mStatus_UnknownErr
);
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).
1113 if( inPort
.NotAnInteger
!= zeroIPPort
.NotAnInteger
)
1115 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
1118 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1119 check_errno( err
, errno
);
1121 // Join the all-DNS multicast group so we receive Multicast DNS packets.
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
);
1129 // Bind to the multicast DNS address and specified port (53 for unicast or 5353 for multicast).
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
);
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
);
1143 // Bind to the interface address and multicast DNS port.
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
);
1153 // Direct multicast packets to the specified interface.
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
);
1159 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1162 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1163 check_errno( err
, errno
);
1165 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1168 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &optionByte
, sizeof( optionByte
) );
1169 check_errno( err
, errno
);
1171 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
1173 option
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1174 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TOS
, (char *) &option
, sizeof( option
) );
1175 check_errno( err
, errno
);
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
);
1183 *outSocketRef
= socketRef
;
1184 socketRef
= kInvalidSocketRef
;
1185 err
= mStatus_NoError
;
1188 if( socketRef
!= kInvalidSocketRef
)
1197 #pragma mark == Commands ==
1200 //===========================================================================================================================
1202 //===========================================================================================================================
1204 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1208 // Clean up any leftover command pipe.
1210 TearDownCommandPipe( inMDNS
);
1212 // Create the pipe device and open it.
1214 pipeDevCreate( kMDNSPipeName
, kMDNSPipeMessageQueueSize
, kMDNSPipeMessageSize
);
1216 inMDNS
->p
->commandPipe
= open( kMDNSPipeName
, O_RDWR
, 0 );
1217 require_errno_action( inMDNS
->p
->commandPipe
, errno
, exit
, err
= mStatus_UnsupportedErr
);
1219 err
= mStatus_NoError
;
1225 //===========================================================================================================================
1226 // TearDownCommandPipe
1227 //===========================================================================================================================
1229 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1231 if( inMDNS
->p
->commandPipe
!= ERROR
)
1233 close( inMDNS
->p
->commandPipe
);
1234 inMDNS
->p
->commandPipe
= ERROR
;
1236 return( mStatus_NoError
);
1239 //===========================================================================================================================
1241 //===========================================================================================================================
1243 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1247 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1249 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1250 require_errno( err
, errno
, exit
);
1252 err
= mStatus_NoError
;
1258 //===========================================================================================================================
1260 //===========================================================================================================================
1262 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1265 MDNSPipeCommandCode commandCode
;
1267 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1269 // Read the command code from the pipe and dispatch it.
1271 err
= read( inMDNS
->p
->commandPipe
, &commandCode
, sizeof( commandCode
) );
1272 require_errno( err
, errno
, exit
);
1274 switch( commandCode
)
1276 case kMDNSPipeCommandCodeReschedule
:
1278 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
1280 dlog( kDebugLevelChatty
, DEBUG_NAME
"reschedule\n" );
1283 case kMDNSPipeCommandCodeReconfigure
:
1284 ProcessCommandReconfigure( inMDNS
);
1287 case kMDNSPipeCommandCodeQuit
:
1289 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
1291 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe quit command\n" );
1292 inMDNS
->p
->quit
= mDNStrue
;
1293 ++inMDNS
->p
->configID
;
1297 dlog( kDebugLevelError
, DEBUG_NAME
"unknown pipe command code (code=0x%08X)\n", commandCode
);
1298 err
= mStatus_BadParamErr
;
1302 err
= mStatus_NoError
;
1308 //===========================================================================================================================
1309 // ProcessCommandReconfigure
1310 //===========================================================================================================================
1312 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
)
1316 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe reconfigure command\n" );
1318 // Tear down the existing interfaces and set up new ones using the new IP info.
1320 mDNSPlatformLock( inMDNS
);
1322 err
= TearDownInterfaceList( inMDNS
);
1325 err
= SetupInterfaceList( inMDNS
);
1328 mDNSPlatformUnlock( inMDNS
);
1330 // Inform clients of the change.
1332 if( inMDNS
->MainCallback
)
1334 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1337 // Force mDNS to update.
1339 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
1341 // Bump the config ID so the main processing loop detects the configuration change.
1343 ++inMDNS
->p
->configID
;
1348 #pragma mark == Threads ==
1351 //===========================================================================================================================
1353 //===========================================================================================================================
1355 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
)
1360 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
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.
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
);
1371 err
= mStatus_NoError
;
1374 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld, id=%d)\n", err
, task
);
1378 //===========================================================================================================================
1380 //===========================================================================================================================
1382 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
)
1386 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread\n" );
1389 // Send a quit command to cause the thread to exit.
1391 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
1393 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
1395 if( inMDNS
->p
->quitEvent
)
1397 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
1400 err
= mStatus_NoError
;
1402 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread done (err=%ld)\n", err
);
1406 //===========================================================================================================================
1408 //===========================================================================================================================
1410 mDNSlocal
void Task( mDNS
*inMDNS
)
1414 MDNSInterfaceItem
* item
;
1417 struct timeval timeout
;
1419 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting\n" );
1422 // Set up everything up.
1424 err
= TaskInit( inMDNS
);
1425 require_noerr( err
, exit
);
1427 // Main Processing Loop.
1429 while( !inMDNS
->p
->quit
)
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.
1434 TaskSetupReadSet( inMDNS
, &allReadSet
, &maxSocket
);
1435 configID
= inMDNS
->p
->configID
;
1436 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting processing loop (configID=%ld)\n", configID
);
1438 while( configID
== inMDNS
->p
->configID
)
1440 mDNSs32 nextTaskTime
;
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.
1451 inMDNS
->p
->rescheduled
= 0;
1452 nextTaskTime
= mDNS_Execute( inMDNS
);
1453 TaskSetupTimeout( nextTaskTime
, &timeout
);
1455 // Wait until something occurs (e.g. command, incoming packet, or timeout).
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
);
1464 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1466 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task timeout occurred (%ld)\n", mDNSPlatformTimeNow() );
1470 // Scan the read set to determine if any sockets have something pending and process them.
1473 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1475 if( FD_ISSET( item
->multicastSocketRef
, &readSet
) )
1477 TaskProcessPacket( inMDNS
, item
, item
->multicastSocketRef
);
1480 if( FD_ISSET( item
->unicastSocketRef
, &readSet
) )
1482 TaskProcessPacket( inMDNS
, item
, item
->unicastSocketRef
);
1487 // Check for a pending command and process it.
1489 if( FD_ISSET( inMDNS
->p
->commandPipe
, &readSet
) )
1491 ProcessCommand( inMDNS
);
1499 // Signal we've quit.
1501 check( inMDNS
->p
->quitEvent
);
1502 semGive( inMDNS
->p
->quitEvent
);
1504 dlog( kDebugLevelInfo
, DEBUG_NAME
"task ended\n" );
1507 //===========================================================================================================================
1509 //===========================================================================================================================
1511 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1515 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init\n" );
1516 check( inMDNS
->p
->readyEvent
);
1518 inMDNS
->p
->task
= taskIdSelf();
1520 err
= SetupCommandPipe( inMDNS
);
1521 require_noerr( err
, exit
);
1523 SetupNames( inMDNS
);
1525 err
= SetupInterfaceList( inMDNS
);
1526 require_noerr( err
, exit
);
1529 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1531 inMDNS
->p
->taskInitErr
= err
;
1532 semGive( inMDNS
->p
->readyEvent
);
1534 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init done (err=%ld)\n", err
);
1538 //===========================================================================================================================
1540 //===========================================================================================================================
1542 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
)
1544 MDNSInterfaceItem
* item
;
1547 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set\n" );
1549 check( outReadSet
);
1550 check( outMaxSocket
);
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.
1555 FD_ZERO( outReadSet
);
1558 // Add all the receiving sockets to the read set.
1560 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1562 FD_SET( item
->multicastSocketRef
, outReadSet
);
1563 FD_SET( item
->unicastSocketRef
, outReadSet
);
1564 if( item
->multicastSocketRef
> maxSocket
)
1566 maxSocket
= item
->multicastSocketRef
;
1568 if( item
->unicastSocketRef
> maxSocket
)
1570 maxSocket
= item
->unicastSocketRef
;
1574 // Add the command pipe to the read set.
1576 FD_SET( inMDNS
->p
->commandPipe
, outReadSet
);
1577 if( inMDNS
->p
->commandPipe
> maxSocket
)
1579 maxSocket
= inMDNS
->p
->commandPipe
;
1581 check( maxSocket
> 0 );
1582 *outMaxSocket
= maxSocket
;
1584 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set done (maxSocket=%d)\n", maxSocket
);
1587 //===========================================================================================================================
1589 //===========================================================================================================================
1591 mDNSlocal
void TaskSetupTimeout( mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
)
1595 // Calculate how long to wait before performing idle processing.
1597 delta
= inNextTaskTime
- mDNSPlatformTimeNow();
1600 // The next task time is now or in the past. Set the timeout to fire immediately.
1602 outTimeout
->tv_sec
= 0;
1603 outTimeout
->tv_usec
= 0;
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.
1610 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1611 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicrosecondsMultiplier
;
1613 // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
1615 if( outTimeout
->tv_usec
>= 1000000L )
1617 outTimeout
->tv_sec
+= 1;
1618 outTimeout
->tv_usec
= 0;
1622 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task in %ld:%ld seconds (%ld)\n",
1623 outTimeout
->tv_sec
, outTimeout
->tv_usec
, inNextTaskTime
);
1625 //===========================================================================================================================
1626 // TaskProcessPacket
1627 //===========================================================================================================================
1629 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
)
1632 mDNSBool isMulticast
;
1634 struct sockaddr_in addr
;
1636 mDNSu8
* packetEndPtr
;
1642 isMulticast
= ( inSocketRef
== inItem
->multicastSocketRef
);
1644 // Receive the packet.
1646 addrSize
= sizeof( addr
);
1647 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1651 // Set up the src/dst/interface info.
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
;
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" );
1671 // Dispatch the packet to mDNS.
1673 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1674 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inItem
->hostSet
.InterfaceID
, 255 );
1679 inItem
->recvMulticastCounter
+= isMulticast
;
1680 inItem
->recvUnicastCounter
+= !isMulticast
;
1681 inItem
->recvErrorCounter
+= ( n
< 0 );
1686 #pragma mark == Utilities ==
1689 #if( TARGET_NON_APPLE )
1690 //===========================================================================================================================
1691 // GenerateUniqueHostName
1693 // Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
1694 //===========================================================================================================================
1696 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
)
1698 DEBUG_UNUSED( ioSeed
);
1700 // $$$ Non-Apple Platforms: Fill in appropriate name for device.
1702 mDNSPlatformStrCopy( kMDNSDefaultName
, outName
);
1705 //===========================================================================================================================
1706 // GenerateUniqueDNSName
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 //===========================================================================================================================
1712 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
)
1714 DEBUG_UNUSED( ioSeed
);
1716 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
1718 mDNSPlatformStrCopy( kMDNSDefaultName
, outName
);
1726 //===========================================================================================================================
1728 //===========================================================================================================================
1730 int getifaddrs( struct ifaddrs
**outAddrs
)
1733 struct ifaddrs
* head
;
1734 struct ifaddrs
** next
;
1735 struct ifaddrs
* ifa
;
1738 char ipString
[ INET_ADDR_LEN
];
1747 ifp
= ifIndexToIfp( i
);
1754 // Allocate and initialize the ifaddrs structure and attach it to the linked list.
1756 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1757 require_action( ifa
, exit
, err
= ENOMEM
);
1760 next
= &ifa
->ifa_next
;
1764 ifa
->ifa_name
= (char *) malloc( 16 );
1765 require_action( ifa
->ifa_name
, exit
, err
= ENOMEM
);
1767 n
= sprintf( ifa
->ifa_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
1768 require_action( n
< 16, exit
, err
= ENOBUFS
);
1770 // Fetch the address.
1772 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( struct sockaddr_in
) );
1773 require_action( ifa
->ifa_addr
, exit
, err
= ENOMEM
);
1775 ipString
[ 0 ] = '\0';
1776 #if( TARGET_NON_APPLE )
1777 err
= ifAddrGet( ifa
->ifa_name
, ipString
);
1778 require_noerr( err
, exit
);
1780 err
= ifAddrGetNonAlias( ifa
->ifa_name
, ipString
);
1781 require_noerr( err
, exit
);
1784 err
= sock_pton( ipString
, AF_INET
, ifa
->ifa_addr
, 0, NULL
);
1785 require_noerr( err
, exit
);
1789 ifa
->ifa_flags
= ifp
->if_flags
;
1804 freeifaddrs( head
);
1809 //===========================================================================================================================
1811 //===========================================================================================================================
1813 void freeifaddrs( struct ifaddrs
*inAddrs
)
1818 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
1820 for( p
= inAddrs
; p
; p
= q
)
1826 free( p
->ifa_name
);
1831 free( p
->ifa_addr
);
1834 if( p
->ifa_netmask
)
1836 free( p
->ifa_netmask
);
1837 p
->ifa_netmask
= NULL
;
1839 if( p
->ifa_dstaddr
)
1841 free( p
->ifa_dstaddr
);
1842 p
->ifa_dstaddr
= NULL
;
1846 free( p
->ifa_data
);
1853 //===========================================================================================================================
1855 //===========================================================================================================================
1857 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
1861 if( inFamily
== AF_INET
)
1863 struct sockaddr_in
* ipv4
;
1865 if( inAddrSize
== 0 )
1867 inAddrSize
= sizeof( struct sockaddr_in
);
1869 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1875 ipv4
= (struct sockaddr_in
*) outAddr
;
1876 err
= inet_aton( (char *) inString
, &ipv4
->sin_addr
);
1879 ipv4
->sin_family
= AF_INET
;
1882 *outAddrSize
= sizeof( struct sockaddr_in
);
1886 #if( defined( AF_INET6 ) )
1887 else if( inFamily
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
1903 //===========================================================================================================================
1905 //===========================================================================================================================
1907 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
1909 const struct sockaddr
* addr
;
1911 addr
= (const struct sockaddr
*) inAddr
;
1912 if( addr
->sa_family
== AF_INET
)
1914 struct sockaddr_in
* ipv4
;
1916 if( inAddrSize
== 0 )
1918 inAddrSize
= sizeof( struct sockaddr_in
);
1920 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1926 if( inBufferSize
< 16 )
1933 ipv4
= (struct sockaddr_in
*) addr
;
1934 inet_ntoa_b( ipv4
->sin_addr
, inBuffer
);
1936 #if( defined( AF_INET6 ) )
1937 else if( addr
->sa_family
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
1939 errno
= EAFNOSUPPORT
;
1946 errno
= EAFNOSUPPORT
;
1957 #pragma mark == Debugging ==
1962 void mDNSShow( BOOL inShowRecords
);
1963 void mDNSShowRecords( void );
1964 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
);
1966 //===========================================================================================================================
1968 //===========================================================================================================================
1970 void mDNSShow( BOOL inShowRecords
)
1972 MDNSInterfaceItem
* item
;
1978 printf( "### mDNS not initialized\n" );
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 ] );
2006 printf( "\n-- mDNS interfaces --\n" );
2008 for( item
= gMDNSPtr
->p
->interfaceList
; item
; item
= item
->next
)
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" );
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
);
2040 //===========================================================================================================================
2042 //===========================================================================================================================
2044 void mDNSShowRecords( void )
2046 MDNSInterfaceItem
* item
;
2048 AuthRecord
* record
;
2051 printf( "\n-- mDNS resource records --\n" );
2053 for( record
= gMDNSPtr
->ResourceRecords
; record
; record
= record
->next
)
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
);
2066 //===========================================================================================================================
2068 //===========================================================================================================================
2070 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
)
2077 printf( "\nTXT record (%u bytes):\n\n", inTXTSize
);
2079 p
= (const mDNSu8
*) inTXT
;
2080 end
= p
+ inTXTSize
;
2086 if( ( p
+ size
) > end
)
2088 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
2091 printf( "%2d (%3d bytes): \"%.*s\"\n", i
, size
, size
, p
);