1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Contains: mDNS platform plugin for VxWorks.
19 Copyright: Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
21 Notes for non-Apple platforms:
23 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
27 - Add support for IPv6 (needs VxWorks IPv6 support).
30 // Set up the debug library to use the default category (see DebugServicesLite.h for details).
32 #if ( !TARGET_NON_APPLE )
33 #define DEBUG_USE_DEFAULT_CATEGORY 1
42 #include <sys/types.h>
43 #include <arpa/inet.h>
45 #include <netinet/if_ether.h>
46 #include <netinet/in.h>
47 #include <netinet/ip.h>
48 #include <sys/ioctl.h>
49 #include <sys/socket.h>
56 #include "selectLib.h"
65 #if ( !TARGET_NON_APPLE )
66 #include "ACP/ACPUtilities.h"
67 #include "Support/DebugServicesLite.h"
68 #include "Support/MiscUtilities.h"
71 #include "mDNSEmbeddedAPI.h"
73 #include "mDNSVxWorks.h"
76 #pragma mark == Preprocessor ==
79 //===========================================================================================================================
81 //===========================================================================================================================
83 #if ( !TARGET_NON_APPLE )
84 debug_log_new_default_category( mdns
);
88 #pragma mark == Constants ==
91 //===========================================================================================================================
93 //===========================================================================================================================
95 #define DEBUG_NAME "[mDNS] "
97 #define kMDNSDefaultName "My-Device"
99 #define kMDNSTaskName "tMDNS"
100 #define kMDNSTaskPriority 102
101 #define kMDNSTaskStackSize 49152
103 #define kMDNSPipeName "/pipe/mDNS"
104 #define kMDNSPipeMessageQueueSize 32
105 #define kMDNSPipeMessageSize 1
107 #define kInvalidSocketRef -1
109 typedef uint8_t MDNSPipeCommandCode
;
112 kMDNSPipeCommandCodeInvalid
= 0,
113 kMDNSPipeCommandCodeReschedule
= 1,
114 kMDNSPipeCommandCodeReconfigure
= 2,
115 kMDNSPipeCommandCodeQuit
= 3
119 #pragma mark == Structures ==
122 //===========================================================================================================================
124 //===========================================================================================================================
126 typedef int MDNSSocketRef
;
128 struct MDNSInterfaceItem
130 MDNSInterfaceItem
* next
;
132 MDNSSocketRef multicastSocketRef
;
133 MDNSSocketRef sendingSocketRef
;
134 NetworkInterfaceInfo hostSet
;
135 mDNSBool hostRegistered
;
137 int sendMulticastCounter
;
138 int sendUnicastCounter
;
139 int sendErrorCounter
;
142 int recvErrorCounter
;
147 #pragma mark == Macros ==
150 //===========================================================================================================================
152 //===========================================================================================================================
154 #if ( TARGET_NON_APPLE )
156 // Do-nothing versions of the debugging macros for non-Apple platforms.
158 #define check(assertion)
159 #define check_string( assertion, cstring )
160 #define check_noerr(err)
161 #define check_noerr_string( error, cstring )
162 #define check_errno( assertion, errno_value )
163 #define debug_string( cstring )
164 #define require( assertion, label ) do { if( !(assertion) ) goto label;} while(0)
165 #define require_string( assertion, label, string ) require(assertion, label)
166 #define require_quiet( assertion, label ) require( assertion, label )
167 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label;} while(0)
168 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
169 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
170 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
171 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
172 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
173 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
174 #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label;} while(0)
175 #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
177 #define dlog( ARGS... )
179 #define DEBUG_UNUSED( X ) (void)( X )
183 #pragma mark == Prototypes ==
186 //===========================================================================================================================
188 //===========================================================================================================================
190 // ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
192 extern struct ifnet
* ifIndexToIfp(int ifIndex
);
194 // Platform Internals
196 mDNSlocal
void SetupNames( mDNS
* const inMDNS
);
197 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
198 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
199 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
);
200 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
);
204 const struct ifaddrs
* inAddr
,
206 MDNSSocketRef
* outSocketRef
);
210 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
211 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
212 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
213 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
214 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
);
218 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
);
219 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
);
220 mDNSlocal
void Task( mDNS
*inMDNS
);
221 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
222 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
);
223 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
);
224 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
);
228 #if ( TARGET_NON_APPLE )
229 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
);
230 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
);
233 // Platform Accessors
239 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
240 struct mDNSPlatformInterfaceInfo
246 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
247 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
254 #pragma mark == Globals ==
257 //===========================================================================================================================
259 //===========================================================================================================================
261 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
262 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
263 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier
= 0;
267 mDNSs32 mDNSPlatformOneSecond
;
271 #pragma mark == Public APIs ==
274 //===========================================================================================================================
276 //===========================================================================================================================
278 void mDNSReconfigure( void )
280 // Send a "reconfigure" command to the MDNS task.
284 SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
290 #pragma mark == Platform Support ==
293 //===========================================================================================================================
295 //===========================================================================================================================
297 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
301 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init\n" );
303 // Initialize variables.
305 mDNSPlatformMemZero( &gMDNSPlatformSupport
, sizeof( gMDNSPlatformSupport
) );
306 inMDNS
->p
= &gMDNSPlatformSupport
;
307 inMDNS
->p
->commandPipe
= ERROR
;
308 inMDNS
->p
->task
= ERROR
;
309 inMDNS
->p
->rescheduled
= 1; // Default to rescheduled until fully initialized.
310 mDNSPlatformOneSecond
= sysClkRateGet();
311 gMDNSTicksToMicrosecondsMultiplier
= ( 1000000L / mDNSPlatformOneSecond
);
313 // Allocate semaphores.
315 inMDNS
->p
->lockID
= semMCreate( SEM_Q_FIFO
);
316 require_action( inMDNS
->p
->lockID
, exit
, err
= mStatus_NoMemoryErr
);
318 inMDNS
->p
->readyEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
319 require_action( inMDNS
->p
->readyEvent
, exit
, err
= mStatus_NoMemoryErr
);
321 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
322 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
326 // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
327 // stack space issues. Some of the initialization may require a larger stack than the current task supports.
329 err
= SetupTask( inMDNS
);
330 require_noerr( err
, exit
);
332 err
= semTake( inMDNS
->p
->readyEvent
, WAIT_FOREVER
);
333 require_noerr( err
, exit
);
334 err
= inMDNS
->p
->taskInitErr
;
335 require_noerr( err
, exit
);
337 mDNSCoreInitComplete( inMDNS
, err
);
342 mDNSPlatformClose( inMDNS
);
344 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
348 //===========================================================================================================================
350 //===========================================================================================================================
352 void mDNSPlatformClose( mDNS
* const inMDNS
)
356 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close\n" );
359 // Tear everything down.
361 err
= TearDownTask( inMDNS
);
364 err
= TearDownInterfaceList( inMDNS
);
367 err
= TearDownCommandPipe( inMDNS
);
372 // Release semaphores.
374 if( inMDNS
->p
->quitEvent
)
376 semDelete( inMDNS
->p
->quitEvent
);
377 inMDNS
->p
->quitEvent
= 0;
379 if( inMDNS
->p
->readyEvent
)
381 semDelete( inMDNS
->p
->readyEvent
);
382 inMDNS
->p
->readyEvent
= 0;
384 if( inMDNS
->p
->lockID
)
386 semDelete( inMDNS
->p
->lockID
);
387 inMDNS
->p
->lockID
= 0;
390 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close done\n" );
393 //===========================================================================================================================
394 // mDNSPlatformSendUDP
395 //===========================================================================================================================
399 const mDNS
* const inMDNS
,
400 const void * const inMsg
,
401 const mDNSu8
* const inMsgEnd
,
402 mDNSInterfaceID inInterfaceID
,
403 const mDNSAddr
* inDstIP
,
404 mDNSIPPort inDstPort
)
407 MDNSInterfaceItem
* item
;
408 struct sockaddr_in addr
;
411 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
418 check( inInterfaceID
);
420 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
422 err
= mStatus_BadParamErr
;
427 // Make sure the InterfaceID is valid.
429 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
431 if( item
== (MDNSInterfaceItem
*) inInterfaceID
)
436 require_action( item
, exit
, err
= mStatus_NoSuchNameErr
);
441 item
= (MDNSInterfaceItem
*) inInterfaceID
;
442 check( item
->sendingSocketRef
!= kInvalidSocketRef
);
444 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
445 addr
.sin_family
= AF_INET
;
446 addr
.sin_port
= inDstPort
.NotAnInteger
;
447 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
449 n
= inMsgEnd
- ( (const mDNSu8
* const) inMsg
);
450 n
= sendto( item
->sendingSocketRef
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
451 check_errno( n
, errno
);
453 item
->sendErrorCounter
+= ( n
< 0 );
454 item
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
455 item
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
457 dlog( kDebugLevelChatty
, DEBUG_NAME
"sent (to=%u.%u.%u.%u:%hu)\n",
458 inDstIP
->ip
.v4
.b
[ 0 ], inDstIP
->ip
.v4
.b
[ 1 ], inDstIP
->ip
.v4
.b
[ 2 ], inDstIP
->ip
.v4
.b
[ 3 ],
459 htons( inDstPort
.NotAnInteger
) );
460 err
= mStatus_NoError
;
463 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
467 //===========================================================================================================================
468 // Connection-oriented (TCP) functions
469 //===========================================================================================================================
471 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
472 TCPConnectionCallback callback
, void *context
, int *descriptor
)
475 (void)dstport
; // Unused
476 (void)InterfaceID
; // Unused
477 (void)callback
; // Unused
478 (void)context
; // Unused
479 (void)descriptor
; // Unused
480 return(mStatus_UnsupportedErr
);
483 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
488 mDNSexport
long mDNSPlatformReadTCP(int sd
, void *buf
, unsigned long buflen
)
492 (void)buflen
; // Unused
496 mDNSexport
long mDNSPlatformWriteTCP(int sd
, const char *msg
, unsigned long len
)
504 //===========================================================================================================================
506 //===========================================================================================================================
508 void mDNSPlatformLock( const mDNS
* const inMDNS
)
510 check( inMDNS
->p
->lockID
);
512 if( inMDNS
->p
->lockID
)
514 #if ( TARGET_NON_APPLE )
515 semTake( inMDNS
->p
->lockID
, WAIT_FOREVER
);
517 semTakeDeadlockDetect( inMDNS
->p
->lockID
, WAIT_FOREVER
);
522 //===========================================================================================================================
523 // mDNSPlatformUnlock
524 //===========================================================================================================================
526 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
530 check( inMDNS
->p
->lockID
);
531 check_string( inMDNS
->p
->task
!= ERROR
, "mDNS task not started" );
533 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
534 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
535 // (a) handle immediate work (if any) resulting from this API call
536 // (b) calculate the next sleep time between now and the next interesting event
538 if( ( mDNS_TimeNow(inMDNS
) - inMDNS
->NextScheduledEvent
) >= 0 )
540 // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
541 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
543 if( ( inMDNS
->p
->rescheduled
++ == 0 ) && ( taskIdSelf() != inMDNS
->p
->task
) )
545 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
549 if( inMDNS
->p
->lockID
)
551 semGive( inMDNS
->p
->lockID
);
555 //===========================================================================================================================
556 // mDNSPlatformStrLen
557 //===========================================================================================================================
559 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
563 return( (mDNSu32
) strlen( (const char *) inSrc
) );
566 //===========================================================================================================================
567 // mDNSPlatformStrCopy
568 //===========================================================================================================================
570 void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
575 strcpy( (char *) inDst
, (const char*) inSrc
);
578 //===========================================================================================================================
579 // mDNSPlatformMemCopy
580 //===========================================================================================================================
582 void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
587 memcpy( inDst
, inSrc
, inSize
);
590 //===========================================================================================================================
591 // mDNSPlatformMemSame
592 //===========================================================================================================================
594 mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
599 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
602 //===========================================================================================================================
603 // mDNSPlatformMemZero
604 //===========================================================================================================================
606 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
610 memset( inDst
, 0, inSize
);
613 //===========================================================================================================================
614 // mDNSPlatformMemAllocate
615 //===========================================================================================================================
617 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
623 mem
= malloc( inSize
);
629 //===========================================================================================================================
630 // mDNSPlatformMemFree
631 //===========================================================================================================================
633 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
640 //===========================================================================================================================
641 // mDNSPlatformRandomSeed
642 //===========================================================================================================================
644 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
649 //===========================================================================================================================
650 // mDNSPlatformTimeInit
651 //===========================================================================================================================
653 mDNSexport mStatus
mDNSPlatformTimeInit( void )
655 // No special setup is required on VxWorks -- we just use tickGet().
656 return( mStatus_NoError
);
659 //===========================================================================================================================
660 // mDNSPlatformRawTime
661 //===========================================================================================================================
663 mDNSs32
mDNSPlatformRawTime( void )
665 return( (mDNSs32
) tickGet() );
668 //===========================================================================================================================
670 //===========================================================================================================================
672 mDNSexport mDNSs32
mDNSPlatformUTC( void )
677 //===========================================================================================================================
678 // mDNSPlatformInterfaceNameToID
679 //===========================================================================================================================
681 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
684 MDNSInterfaceItem
* ifd
;
690 // Search for an interface with the specified name,
692 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
694 if( strcmp( ifd
->name
, inName
) == 0 )
701 err
= mStatus_NoSuchNameErr
;
709 *outID
= (mDNSInterfaceID
) ifd
;
711 err
= mStatus_NoError
;
717 //===========================================================================================================================
718 // mDNSPlatformInterfaceIDToInfo
719 //===========================================================================================================================
721 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
724 MDNSInterfaceItem
* ifd
;
730 // Search for an interface with the specified ID,
732 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
734 if( ifd
== (MDNSInterfaceItem
*) inID
)
741 err
= mStatus_NoSuchNameErr
;
747 outInfo
->name
= ifd
->name
;
748 outInfo
->ip
= ifd
->hostSet
.ip
;
749 err
= mStatus_NoError
;
755 //===========================================================================================================================
757 //===========================================================================================================================
759 #if ( MDNS_DEBUGMSGS )
760 mDNSexport
void debugf_( const char *format
, ... )
766 va_start( args
, format
);
767 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
770 dlog( kDebugLevelInfo
, "%s\n", buffer
);
774 //===========================================================================================================================
776 //===========================================================================================================================
778 #if ( MDNS_DEBUGMSGS > 1 )
779 mDNSexport
void verbosedebugf_( const char *format
, ... )
785 va_start( args
, format
);
786 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
789 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
793 //===========================================================================================================================
795 //===========================================================================================================================
797 void LogMsg( const char *inFormat
, ... )
803 va_start( args
, inFormat
);
804 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
807 dlog( kDebugLevelWarning
, "%s\n", buffer
);
812 #pragma mark == Platform Internals ==
815 //===========================================================================================================================
817 //===========================================================================================================================
819 mDNSlocal
void SetupNames( mDNS
* const inMDNS
)
821 char tempCString
[ 128 ];
822 mDNSu8 tempPString
[ 128 ];
825 // Set up the host name.
827 tempCString
[ 0 ] = '\0';
828 GenerateUniqueHostName( tempCString
, NULL
);
829 check( tempCString
[ 0 ] != '\0' );
830 if( tempCString
[ 0 ] == '\0' )
832 // No name so use the default.
834 strcpy( tempCString
, kMDNSDefaultName
);
836 inMDNS
->nicelabel
.c
[ 0 ] = strlen( tempCString
);
837 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempCString
, inMDNS
->nicelabel
.c
[ 0 ] );
838 check( inMDNS
->nicelabel
.c
[ 0 ] > 0 );
840 // Set up the DNS name.
842 tempCString
[ 0 ] = '\0';
843 GenerateUniqueDNSName( tempCString
, NULL
);
844 if( tempCString
[ 0 ] != '\0' )
846 tempPString
[ 0 ] = strlen( tempCString
);
847 memcpy( &tempPString
[ 1 ], tempCString
, tempPString
[ 0 ] );
848 namePtr
= tempPString
;
852 // No DNS name so use the host name.
854 namePtr
= inMDNS
->nicelabel
.c
;
856 ConvertUTF8PstringToRFC1034HostLabel( namePtr
, &inMDNS
->hostlabel
);
857 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
859 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
861 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
863 check( inMDNS
->hostlabel
.c
[ 0 ] > 0 );
865 mDNS_SetFQDN( inMDNS
);
867 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
868 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
871 //===========================================================================================================================
872 // SetupInterfaceList
873 //===========================================================================================================================
875 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
878 struct ifaddrs
* addrs
;
882 MDNSInterfaceItem
** next
;
883 MDNSInterfaceItem
* item
;
887 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
890 // Tear down any existing interfaces that may be set up.
892 TearDownInterfaceList( inMDNS
);
893 inMDNS
->p
->interfaceList
= NULL
;
894 next
= &inMDNS
->p
->interfaceList
;
896 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
898 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTOPOINT
;
899 flagTest
= IFF_UP
| IFF_MULTICAST
;
901 err
= getifaddrs( &addrs
);
902 require_noerr( err
, exit
);
904 for( p
= addrs
; p
; p
= p
->ifa_next
)
906 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
908 err
= SetupInterface( inMDNS
, p
, &item
);
909 require_noerr( err
, exit
);
915 err
= mStatus_NoError
;
920 freeifaddrs( addrs
);
924 TearDownInterfaceList( inMDNS
);
926 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
930 //===========================================================================================================================
931 // TearDownInterfaceList
932 //===========================================================================================================================
934 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
936 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
939 // Tear down all the interfaces.
941 while( inMDNS
->p
->interfaceList
)
943 MDNSInterfaceItem
* item
;
945 item
= inMDNS
->p
->interfaceList
;
946 inMDNS
->p
->interfaceList
= item
->next
;
948 TearDownInterface( inMDNS
, item
);
951 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
952 return( mStatus_NoError
);
955 //===========================================================================================================================
957 //===========================================================================================================================
959 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
)
962 MDNSInterfaceItem
* item
;
963 MDNSSocketRef socketRef
;
964 const struct sockaddr_in
* ipv4
, *mask
;
966 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface (name=%s)\n", inAddr
->ifa_name
);
969 check( inAddr
->ifa_addr
);
970 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
971 mask
= (const struct sockaddr_in
*) inAddr
->ifa_netmask
;
974 // Allocate memory for the info item.
976 item
= (MDNSInterfaceItem
*) calloc( 1, sizeof( *item
) );
977 require_action( item
, exit
, err
= mStatus_NoMemoryErr
);
978 strcpy( item
->name
, inAddr
->ifa_name
);
979 item
->multicastSocketRef
= kInvalidSocketRef
;
980 item
->sendingSocketRef
= kInvalidSocketRef
;
982 // Set up the multicast DNS (port 5353) socket for this interface.
984 err
= SetupSocket( inMDNS
, inAddr
, MulticastDNSPort
, &socketRef
);
985 require_noerr( err
, exit
);
986 item
->multicastSocketRef
= socketRef
;
988 // Set up the sending socket for this interface.
990 err
= SetupSocket( inMDNS
, inAddr
, zeroIPPort
, &socketRef
);
991 require_noerr( err
, exit
);
992 item
->sendingSocketRef
= socketRef
;
994 // Register this interface with mDNS.
996 item
->hostSet
.InterfaceID
= (mDNSInterfaceID
) item
;
997 item
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
998 item
->hostSet
.ip
.ip
.v4
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
999 item
->hostSet
.mask
.type
= mDNSAddrType_IPv4
;
1000 item
->hostSet
.mask
.ip
.v4
.NotAnInteger
= mask
->sin_addr
.s_addr
;
1001 item
->hostSet
.ifname
[0] = 0;
1002 item
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1003 item
->hostSet
.McastTxRx
= mDNStrue
;
1005 err
= mDNS_RegisterInterface( inMDNS
, &item
->hostSet
, mDNSfalse
);
1006 require_noerr( err
, exit
);
1007 item
->hostRegistered
= mDNStrue
;
1009 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1010 item
->hostSet
.ip
.ip
.v4
.b
[ 0 ], item
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1011 item
->hostSet
.ip
.ip
.v4
.b
[ 2 ], item
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1021 TearDownInterface( inMDNS
, item
);
1023 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (name=%s, err=%ld)\n", inAddr
->ifa_name
, err
);
1027 //===========================================================================================================================
1028 // TearDownInterface
1029 //===========================================================================================================================
1031 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
)
1033 MDNSSocketRef socketRef
;
1038 // Deregister this interface with mDNS.
1040 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1041 inItem
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1042 inItem
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1044 if( inItem
->hostRegistered
)
1046 inItem
->hostRegistered
= mDNSfalse
;
1047 mDNS_DeregisterInterface( inMDNS
, &inItem
->hostSet
, mDNSfalse
);
1050 // Close the multicast socket.
1052 socketRef
= inItem
->multicastSocketRef
;
1053 inItem
->multicastSocketRef
= kInvalidSocketRef
;
1054 if( socketRef
!= kInvalidSocketRef
)
1056 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1060 // Close the sending socket.
1062 socketRef
= inItem
->sendingSocketRef
;
1063 inItem
->sendingSocketRef
= kInvalidSocketRef
;
1064 if( socketRef
!= kInvalidSocketRef
)
1066 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down sending socket %d\n", socketRef
);
1070 // Free the memory used by the interface info.
1073 return( mStatus_NoError
);
1076 //===========================================================================================================================
1078 //===========================================================================================================================
1082 mDNS
* const inMDNS
,
1083 const struct ifaddrs
* inAddr
,
1085 MDNSSocketRef
* outSocketRef
)
1088 MDNSSocketRef socketRef
;
1090 unsigned char optionByte
;
1091 struct ip_mreq mreq
;
1092 const struct sockaddr_in
* ipv4
;
1093 struct sockaddr_in addr
;
1096 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1099 check( inAddr
->ifa_addr
);
1100 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1101 check( outSocketRef
);
1103 // Set up a UDP socket for multicast DNS.
1105 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1106 require_errno_action( socketRef
, errno
, exit
, err
= mStatus_UnknownErr
);
1108 // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
1109 // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
1110 // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
1111 // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
1112 // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
1114 if( inPort
.NotAnInteger
!= zeroIPPort
.NotAnInteger
)
1116 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
1119 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1120 check_errno( err
, errno
);
1122 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1124 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1125 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1126 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1127 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1128 check_errno( err
, errno
);
1130 // Bind to the multicast DNS address and port 5353.
1132 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
1133 addr
.sin_family
= AF_INET
;
1134 addr
.sin_port
= inPort
.NotAnInteger
;
1135 addr
.sin_addr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1136 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1137 check_errno( err
, errno
);
1139 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
1140 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], ntohs( inPort
.NotAnInteger
), socketRef
);
1144 // Bind to the interface address and multicast DNS port.
1146 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1147 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
1148 addr
.sin_family
= AF_INET
;
1149 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1150 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1151 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1152 check_errno( err
, errno
);
1154 // Direct multicast packets to the specified interface.
1156 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1157 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1158 check_errno( err
, errno
);
1160 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1163 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1164 check_errno( err
, errno
);
1166 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1169 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &optionByte
, sizeof( optionByte
) );
1170 check_errno( err
, errno
);
1172 // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
1173 // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
1176 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
1178 option
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1179 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TOS
, (char *) &option
, sizeof( option
) );
1180 check_errno( err
, errno
);
1183 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
1184 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], socketRef
);
1189 *outSocketRef
= socketRef
;
1190 socketRef
= kInvalidSocketRef
;
1191 err
= mStatus_NoError
;
1194 if( socketRef
!= kInvalidSocketRef
)
1203 #pragma mark == Commands ==
1206 //===========================================================================================================================
1208 //===========================================================================================================================
1210 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1214 // Clean up any leftover command pipe.
1216 TearDownCommandPipe( inMDNS
);
1218 // Create the pipe device and open it.
1220 pipeDevCreate( kMDNSPipeName
, kMDNSPipeMessageQueueSize
, kMDNSPipeMessageSize
);
1222 inMDNS
->p
->commandPipe
= open( kMDNSPipeName
, O_RDWR
, 0 );
1223 require_errno_action( inMDNS
->p
->commandPipe
, errno
, exit
, err
= mStatus_UnsupportedErr
);
1225 err
= mStatus_NoError
;
1231 //===========================================================================================================================
1232 // TearDownCommandPipe
1233 //===========================================================================================================================
1235 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1237 if( inMDNS
->p
->commandPipe
!= ERROR
)
1239 close( inMDNS
->p
->commandPipe
);
1240 #ifdef _WRS_VXWORKS_5_X
1241 // pipeDevDelete is not defined in older versions of VxWorks
1242 pipeDevDelete( kMDNSPipeName
, FALSE
);
1244 inMDNS
->p
->commandPipe
= ERROR
;
1246 return( mStatus_NoError
);
1249 //===========================================================================================================================
1251 //===========================================================================================================================
1253 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1257 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1259 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1260 require_errno( err
, errno
, exit
);
1262 err
= mStatus_NoError
;
1268 //===========================================================================================================================
1270 //===========================================================================================================================
1272 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1275 MDNSPipeCommandCode commandCode
;
1277 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1279 // Read the command code from the pipe and dispatch it.
1281 err
= read( inMDNS
->p
->commandPipe
, &commandCode
, sizeof( commandCode
) );
1282 require_errno( err
, errno
, exit
);
1284 switch( commandCode
)
1286 case kMDNSPipeCommandCodeReschedule
:
1288 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
1290 dlog( kDebugLevelChatty
, DEBUG_NAME
"reschedule\n" );
1293 case kMDNSPipeCommandCodeReconfigure
:
1294 ProcessCommandReconfigure( inMDNS
);
1297 case kMDNSPipeCommandCodeQuit
:
1299 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
1301 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe quit command\n" );
1302 inMDNS
->p
->quit
= mDNStrue
;
1303 ++inMDNS
->p
->configID
;
1307 dlog( kDebugLevelError
, DEBUG_NAME
"unknown pipe command code (code=0x%08X)\n", commandCode
);
1308 err
= mStatus_BadParamErr
;
1312 err
= mStatus_NoError
;
1318 //===========================================================================================================================
1319 // ProcessCommandReconfigure
1320 //===========================================================================================================================
1322 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
)
1326 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe reconfigure command\n" );
1328 // Tear down the existing interfaces and set up new ones using the new IP info.
1330 mDNSPlatformLock( inMDNS
);
1332 err
= TearDownInterfaceList( inMDNS
);
1335 err
= SetupInterfaceList( inMDNS
);
1338 mDNSPlatformUnlock( inMDNS
);
1340 // Inform clients of the change.
1342 mDNS_ConfigChanged(m
);
1344 // Force mDNS to update.
1346 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
); // What is this for? Mac OS X does not do this
1348 // Bump the config ID so the main processing loop detects the configuration change.
1350 ++inMDNS
->p
->configID
;
1355 #pragma mark == Threads ==
1358 //===========================================================================================================================
1360 //===========================================================================================================================
1362 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
)
1367 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1370 // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
1371 // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
1372 // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
1374 task
= taskSpawn( kMDNSTaskName
, kMDNSTaskPriority
, 0, kMDNSTaskStackSize
, (FUNCPTR
) Task
,
1375 (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1376 require_action( task
!= ERROR
, exit
, err
= mStatus_NoMemoryErr
);
1378 err
= mStatus_NoError
;
1381 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld, id=%d)\n", err
, task
);
1385 //===========================================================================================================================
1387 //===========================================================================================================================
1389 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
)
1393 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread\n" );
1396 // Send a quit command to cause the thread to exit.
1398 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
1400 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
1402 if( inMDNS
->p
->quitEvent
)
1404 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
1407 err
= mStatus_NoError
;
1409 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread done (err=%ld)\n", err
);
1413 //===========================================================================================================================
1415 //===========================================================================================================================
1417 mDNSlocal
void Task( mDNS
*inMDNS
)
1421 MDNSInterfaceItem
* item
;
1424 struct timeval timeout
;
1426 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting\n" );
1429 // Set up everything up.
1431 err
= TaskInit( inMDNS
);
1432 require_noerr( err
, exit
);
1434 // Main Processing Loop.
1436 while( !inMDNS
->p
->quit
)
1438 // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
1439 // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
1441 TaskSetupReadSet( inMDNS
, &allReadSet
, &maxSocket
);
1442 configID
= inMDNS
->p
->configID
;
1443 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting processing loop (configID=%ld)\n", configID
);
1445 while( configID
== inMDNS
->p
->configID
)
1447 mDNSs32 nextTaskTime
;
1451 // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
1452 // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
1453 // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
1454 // processing packets. This introduces a window for a race condition because the thread wake-up and
1455 // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
1456 // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
1458 inMDNS
->p
->rescheduled
= 0;
1459 nextTaskTime
= mDNS_Execute( inMDNS
);
1460 TaskSetupTimeout( inMDNS
, nextTaskTime
, &timeout
);
1462 // Wait until something occurs (e.g. command, incoming packet, or timeout).
1464 readSet
= allReadSet
;
1465 n
= select( maxSocket
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1466 inMDNS
->p
->rescheduled
= 1;
1467 check_errno( n
, errno
);
1468 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"task select result = %d\n", n
);
1471 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1473 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS
) );
1477 // Scan the read set to determine if any sockets have something pending and process them.
1480 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1482 if( FD_ISSET( item
->multicastSocketRef
, &readSet
) )
1484 TaskProcessPacket( inMDNS
, item
, item
->multicastSocketRef
);
1489 // Check for a pending command and process it.
1491 if( FD_ISSET( inMDNS
->p
->commandPipe
, &readSet
) )
1493 ProcessCommand( inMDNS
);
1501 // Signal we've quit.
1503 check( inMDNS
->p
->quitEvent
);
1504 semGive( inMDNS
->p
->quitEvent
);
1506 dlog( kDebugLevelInfo
, DEBUG_NAME
"task ended\n" );
1509 //===========================================================================================================================
1511 //===========================================================================================================================
1513 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1517 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init\n" );
1518 check( inMDNS
->p
->readyEvent
);
1520 inMDNS
->p
->task
= taskIdSelf();
1522 err
= SetupCommandPipe( inMDNS
);
1523 require_noerr( err
, exit
);
1525 SetupNames( inMDNS
);
1527 err
= SetupInterfaceList( inMDNS
);
1528 require_noerr( err
, exit
);
1531 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1533 inMDNS
->p
->taskInitErr
= err
;
1534 semGive( inMDNS
->p
->readyEvent
);
1536 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init done (err=%ld)\n", err
);
1540 //===========================================================================================================================
1542 //===========================================================================================================================
1544 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
)
1546 MDNSInterfaceItem
* item
;
1549 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set\n" );
1551 check( outReadSet
);
1552 check( outMaxSocket
);
1554 // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
1555 // should never happen since we should always have at least one interface, but it's just to be safe.
1557 FD_ZERO( outReadSet
);
1560 // Add all the receiving sockets to the read set.
1562 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1564 FD_SET( item
->multicastSocketRef
, outReadSet
);
1565 if( item
->multicastSocketRef
> maxSocket
)
1567 maxSocket
= item
->multicastSocketRef
;
1571 // Add the command pipe to the read set.
1573 FD_SET( inMDNS
->p
->commandPipe
, outReadSet
);
1574 if( inMDNS
->p
->commandPipe
> maxSocket
)
1576 maxSocket
= inMDNS
->p
->commandPipe
;
1578 check( maxSocket
> 0 );
1579 *outMaxSocket
= maxSocket
;
1581 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set done (maxSocket=%d)\n", maxSocket
);
1584 //===========================================================================================================================
1586 //===========================================================================================================================
1588 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
)
1592 // Calculate how long to wait before performing idle processing.
1594 delta
= inNextTaskTime
- mDNS_TimeNow(inMDNS
);
1597 // The next task time is now or in the past. Set the timeout to fire immediately.
1599 outTimeout
->tv_sec
= 0;
1600 outTimeout
->tv_usec
= 0;
1604 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1605 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1607 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1608 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicrosecondsMultiplier
;
1610 // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
1612 if( outTimeout
->tv_usec
>= 1000000L )
1614 outTimeout
->tv_sec
+= 1;
1615 outTimeout
->tv_usec
= 0;
1619 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task in %ld:%ld seconds (%ld)\n",
1620 outTimeout
->tv_sec
, outTimeout
->tv_usec
, inNextTaskTime
);
1622 //===========================================================================================================================
1623 // TaskProcessPacket
1624 //===========================================================================================================================
1626 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
)
1630 struct sockaddr_in addr
;
1632 mDNSu8
* packetEndPtr
;
1638 // Receive the packet.
1640 addrSize
= sizeof( addr
);
1641 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1645 // Set up the src/dst/interface info.
1647 srcAddr
.type
= mDNSAddrType_IPv4
;
1648 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1649 srcPort
.NotAnInteger
= addr
.sin_port
;
1650 dstAddr
.type
= mDNSAddrType_IPv4
;
1651 dstAddr
.ip
.v4
= AllDNSLinkGroup_v4
.ip
.v4
;
1652 dstPort
= MulticastDNSPort
;
1654 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1655 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1656 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%hu\n",
1657 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1658 ntohs( srcPort
.NotAnInteger
) );
1659 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%hu\n",
1660 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1661 ntohs( dstPort
.NotAnInteger
) );
1662 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = 0x%08X\n", (int) inItem
->hostSet
.InterfaceID
);
1663 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1665 // Dispatch the packet to mDNS.
1667 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1668 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inItem
->hostSet
.InterfaceID
);
1673 inItem
->recvCounter
+= 1;
1674 inItem
->recvErrorCounter
+= ( n
< 0 );
1679 #pragma mark == Utilities ==
1682 #if ( TARGET_NON_APPLE )
1683 //===========================================================================================================================
1684 // GenerateUniqueHostName
1686 // Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
1687 //===========================================================================================================================
1689 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
)
1691 DEBUG_UNUSED( ioSeed
);
1693 // $$$ Non-Apple Platforms: Fill in appropriate name for device.
1695 mDNSPlatformStrCopy( outName
, kMDNSDefaultName
);
1698 //===========================================================================================================================
1699 // GenerateUniqueDNSName
1701 // Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
1702 // implemented to return a unique name.
1703 //===========================================================================================================================
1705 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
)
1707 DEBUG_UNUSED( ioSeed
);
1709 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
1711 mDNSPlatformStrCopy( outName
, kMDNSDefaultName
);
1719 //===========================================================================================================================
1721 //===========================================================================================================================
1723 int getifaddrs( struct ifaddrs
**outAddrs
)
1726 struct ifaddrs
* head
;
1727 struct ifaddrs
** next
;
1728 struct ifaddrs
* ifa
;
1731 char ipString
[ INET_ADDR_LEN
];
1740 ifp
= ifIndexToIfp( i
);
1747 // Allocate and initialize the ifaddrs structure and attach it to the linked list.
1749 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1750 require_action( ifa
, exit
, err
= ENOMEM
);
1753 next
= &ifa
->ifa_next
;
1757 ifa
->ifa_name
= (char *) malloc( 16 );
1758 require_action( ifa
->ifa_name
, exit
, err
= ENOMEM
);
1760 n
= sprintf( ifa
->ifa_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
1761 require_action( n
< 16, exit
, err
= ENOBUFS
);
1763 // Fetch the address.
1765 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( struct sockaddr_in
) );
1766 require_action( ifa
->ifa_addr
, exit
, err
= ENOMEM
);
1768 ipString
[ 0 ] = '\0';
1769 #if ( TARGET_NON_APPLE )
1770 err
= ifAddrGet( ifa
->ifa_name
, ipString
);
1771 require_noerr( err
, exit
);
1773 err
= ifAddrGetNonAlias( ifa
->ifa_name
, ipString
);
1774 require_noerr( err
, exit
);
1777 err
= sock_pton( ipString
, AF_INET
, ifa
->ifa_addr
, 0, NULL
);
1778 require_noerr( err
, exit
);
1782 ifa
->ifa_flags
= ifp
->if_flags
;
1797 freeifaddrs( head
);
1802 //===========================================================================================================================
1804 //===========================================================================================================================
1806 void freeifaddrs( struct ifaddrs
*inAddrs
)
1811 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
1813 for( p
= inAddrs
; p
; p
= q
)
1819 free( p
->ifa_name
);
1824 free( p
->ifa_addr
);
1827 if( p
->ifa_netmask
)
1829 free( p
->ifa_netmask
);
1830 p
->ifa_netmask
= NULL
;
1832 if( p
->ifa_dstaddr
)
1834 free( p
->ifa_dstaddr
);
1835 p
->ifa_dstaddr
= NULL
;
1839 free( p
->ifa_data
);
1846 //===========================================================================================================================
1848 //===========================================================================================================================
1850 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
1854 if( inFamily
== AF_INET
)
1856 struct sockaddr_in
* ipv4
;
1858 if( inAddrSize
== 0 )
1860 inAddrSize
= sizeof( struct sockaddr_in
);
1862 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1868 ipv4
= (struct sockaddr_in
*) outAddr
;
1869 err
= inet_aton( (char *) inString
, &ipv4
->sin_addr
);
1872 ipv4
->sin_family
= AF_INET
;
1875 *outAddrSize
= sizeof( struct sockaddr_in
);
1879 #if ( defined( AF_INET6 ) )
1880 else if( inFamily
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
1896 //===========================================================================================================================
1898 //===========================================================================================================================
1900 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
1902 const struct sockaddr
* addr
;
1904 addr
= (const struct sockaddr
*) inAddr
;
1905 if( addr
->sa_family
== AF_INET
)
1907 struct sockaddr_in
* ipv4
;
1909 if( inAddrSize
== 0 )
1911 inAddrSize
= sizeof( struct sockaddr_in
);
1913 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1919 if( inBufferSize
< 16 )
1926 ipv4
= (struct sockaddr_in
*) addr
;
1927 inet_ntoa_b( ipv4
->sin_addr
, inBuffer
);
1929 #if ( defined( AF_INET6 ) )
1930 else if( addr
->sa_family
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
1932 errno
= EAFNOSUPPORT
;
1939 errno
= EAFNOSUPPORT
;
1950 #pragma mark == Debugging ==
1955 void mDNSShow( BOOL inShowRecords
);
1956 void mDNSShowRecords( void );
1957 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
);
1959 //===========================================================================================================================
1961 //===========================================================================================================================
1963 void mDNSShow( BOOL inShowRecords
)
1965 MDNSInterfaceItem
* item
;
1971 printf( "### mDNS not initialized\n" );
1977 printf( "\n-- mDNS globals --\n" );
1978 printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
1979 printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
1980 printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
1981 printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
1982 printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr
);
1983 printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier
);
1984 printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->lockID
);
1985 printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->readyEvent
);
1986 printf( " taskInitErr = %ld\n", gMDNSPtr
->p
->taskInitErr
);
1987 printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->quitEvent
);
1988 printf( " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
1989 printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->task
);
1990 printf( " quit = %d\n", gMDNSPtr
->p
->quit
);
1991 printf( " configID = %ld\n", gMDNSPtr
->p
->configID
);
1992 printf( " rescheduled = %d\n", gMDNSPtr
->p
->rescheduled
);
1993 printf( " nicelabel = \"%.*s\"\n", gMDNSPtr
->nicelabel
.c
[ 0 ], (char *) &gMDNSPtr
->nicelabel
.c
[ 1 ] );
1994 printf( " hostLabel = \"%.*s\"\n", gMDNSPtr
->hostlabel
.c
[ 0 ], (char *) &gMDNSPtr
->hostlabel
.c
[ 1 ] );
1999 printf( "\n-- mDNS interfaces --\n" );
2001 for( item
= gMDNSPtr
->p
->interfaceList
; item
; item
= item
->next
)
2003 printf( " -- interface %u --\n", n
);
2004 printf( " name = \"%s\"\n", item
->name
);
2005 printf( " multicastSocketRef = %d\n", item
->multicastSocketRef
);
2006 printf( " sendingSocketRef = %d\n", item
->sendingSocketRef
);
2007 ip
= item
->hostSet
.ip
;
2008 printf( " hostSet.ip = %u.%u.%u.%u\n", ip
.ip
.v4
.b
[ 0 ], ip
.ip
.v4
.b
[ 1 ],
2009 ip
.ip
.v4
.b
[ 2 ], ip
.ip
.v4
.b
[ 3 ] );
2010 printf( " hostSet.advertise = %s\n", item
->hostSet
.Advertise
? "YES" : "NO" );
2011 printf( " hostRegistered = %s\n", item
->hostRegistered
? "YES" : "NO" );
2013 printf( " sendMulticastCounter = %d\n", item
->sendMulticastCounter
);
2014 printf( " sendUnicastCounter = %d\n", item
->sendUnicastCounter
);
2015 printf( " sendErrorCounter = %d\n", item
->sendErrorCounter
);
2016 printf( " recvCounter = %d\n", item
->recvCounter
);
2017 printf( " recvErrorCounter = %d\n", item
->recvErrorCounter
);
2018 printf( " recvLoopCounter = %d\n", item
->recvLoopCounter
);
2031 //===========================================================================================================================
2033 //===========================================================================================================================
2035 void mDNSShowRecords( void )
2037 MDNSInterfaceItem
* item
;
2039 AuthRecord
* record
;
2040 char name
[ MAX_ESCAPED_DOMAIN_NAME
];
2042 printf( "\n-- mDNS resource records --\n" );
2044 for( record
= gMDNSPtr
->ResourceRecords
; record
; record
= record
->next
)
2046 item
= (MDNSInterfaceItem
*) record
->resrec
.InterfaceID
;
2047 ConvertDomainNameToCString( &record
->resrec
.name
, name
);
2048 printf( " -- record %d --\n", n
);
2049 printf( " interface = 0x%08X (%s)\n", (int) item
, item
? item
->name
: "<any>" );
2050 printf( " name = \"%s\"\n", name
);
2057 //===========================================================================================================================
2059 //===========================================================================================================================
2061 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
)
2068 printf( "\nTXT record (%u bytes):\n\n", inTXTSize
);
2070 p
= (const mDNSu8
*) inTXT
;
2071 end
= p
+ inTXTSize
;
2077 if( ( p
+ size
) > end
)
2079 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
2082 printf( "%2d (%3d bytes): \"%.*s\"\n", i
, size
, size
, p
);