#if 0
#pragma mark == Configuration ==
#endif
#define DEBUG_NAME "[mDNS] "
#define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
#define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
#define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
#define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough.
#define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines.
#define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details).
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "vxWorks.h"
#include "config.h"
#include <sys/types.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/ifaddrs.h>
#include <netinet6/in6_var.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include "ifLib.h"
#include "inetLib.h"
#include "pipeDrv.h"
#include "selectLib.h"
#include "semLib.h"
#include "sockLib.h"
#include "sysLib.h"
#include "taskLib.h"
#include "tickLib.h"
#include "CommonServices.h"
#include "DebugServices.h"
#include "DNSCommon.h"
#include "mDNSEmbeddedAPI.h"
#include "mDNSVxWorks.h"
#if 0
#pragma mark == Constants ==
#endif
typedef uint8_t MDNSPipeCommandCode;
#define kMDNSPipeCommandCodeInvalid 0
#define kMDNSPipeCommandCodeReschedule 1
#define kMDNSPipeCommandCodeReconfigure 2
#define kMDNSPipeCommandCodeQuit 3
#if 0
#pragma mark == Prototypes ==
#endif
#if ( DEBUG )
mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... );
#define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
#else
#define dmsg( LEVEL, ARGS... )
#endif
#if ( DEBUG && MDNS_DEBUG_PACKETS )
#define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
#else
#define dpkt( LEVEL, ARGS... )
#endif
#define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
#define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC );
mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC );
mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC );
mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC );
mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing );
mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID );
mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex );
mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS );
mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP );
mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS );
mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS );
mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS );
mDNSlocal void Task( mDNS *inMDNS );
mDNSlocal mStatus TaskInit( mDNS *inMDNS );
mDNSlocal void TaskTerm( mDNS *inMDNS );
mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout );
mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock );
mDNSlocal ssize_t
mDNSRecvMsg(
SocketRef inSock,
void * inBuffer,
size_t inBufferSize,
void * outFrom,
size_t inFromSize,
size_t * outFromSize,
mDNSAddr * outDstAddr,
uint32_t * outIndex );
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
struct mDNSPlatformInterfaceInfo
{
const char * name;
mDNSAddr ip;
};
mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
#ifdef __cplusplus
}
#endif
#if 0
#pragma mark == Globals ==
#endif
debug_log_new_default_category( mdns );
mDNSexport mDNSs32 mDNSPlatformOneSecond;
mDNSlocal mDNSs32 gMDNSTicksToMicro = 0;
mDNSlocal mDNS * gMDNSPtr = NULL;
mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
mDNSlocal mDNSBool gMDNSDeferIPv4 = mDNSfalse;
#if ( DEBUG )
DebugLevel gMDNSDebugOverrideLevel = kDebugLevelMax;
#endif
#if 0
#pragma mark -
#endif
void mDNSReconfigure( void )
{
if( gMDNSPtr ) SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure );
}
void mDNSDeferIPv4( mDNSBool inDefer )
{
gMDNSDeferIPv4 = inDefer;
}
#if 0
#pragma mark -
#endif
mStatus mDNSPlatformInit( mDNS * const inMDNS )
{
mStatus err;
int id;
mDNSPlatformOneSecond = sysClkRateGet();
gMDNSTicksToMicro = ( 1000000L / mDNSPlatformOneSecond );
mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
inMDNS->p->unicastSS.info = NULL;
inMDNS->p->unicastSS.sockV4 = kInvalidSocketRef;
inMDNS->p->unicastSS.sockV6 = kInvalidSocketRef;
inMDNS->p->initErr = mStatus_NotInitializedErr;
inMDNS->p->commandPipe = ERROR;
inMDNS->p->taskID = ERROR;
inMDNS->p->lock = semMCreate( SEM_Q_FIFO );
require_action( inMDNS->p->lock, exit, err = mStatus_NoMemoryErr );
inMDNS->p->initEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr );
inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
id = taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR) Task, (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
err = translate_errno( id != ERROR, errno_compat(), mStatus_NoMemoryErr );
require_noerr( err, exit );
err = semTake( inMDNS->p->initEvent, WAIT_FOREVER );
if( err == OK ) err = inMDNS->p->initErr;
require_noerr( err, exit );
gMDNSPtr = inMDNS;
mDNSCoreInitComplete( inMDNS, err );
exit:
if( err ) mDNSPlatformClose( inMDNS );
return( err );
}
void mDNSPlatformClose( mDNS * const inMDNS )
{
mStatus err;
check( inMDNS );
gMDNSPtr = NULL;
if( inMDNS->p->taskID != ERROR )
{
SendCommand( inMDNS, kMDNSPipeCommandCodeQuit );
if( inMDNS->p->quitEvent )
{
err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 );
check_noerr( err );
}
inMDNS->p->taskID = ERROR;
}
ForgetSem( &inMDNS->p->quitEvent );
ForgetSem( &inMDNS->p->initEvent );
ForgetSem( &inMDNS->p->lock );
dmsg( kDebugLevelNotice, DEBUG_NAME "CLOSED\n" );
}
mStatus
mDNSPlatformSendUDP(
const mDNS * const inMDNS,
const void * const inMsg,
const mDNSu8 * const inEnd,
mDNSInterfaceID inInterfaceID,
const mDNSAddr * inDstIP,
mDNSIPPort inDstPort )
{
mStatus err;
NetworkInterfaceInfoVxWorks * info;
SocketRef sock;
struct sockaddr_storage to;
int n;
info = (NetworkInterfaceInfoVxWorks *) inInterfaceID;
if( inDstIP->type == mDNSAddrType_IPv4 )
{
struct sockaddr_in * sa4;
sa4 = (struct sockaddr_in *) &to;
sa4->sin_len = sizeof( *sa4 );
sa4->sin_family = AF_INET;
sa4->sin_port = inDstPort.NotAnInteger;
sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
sock = info ? info->ss.sockV4 : inMDNS->p->unicastSS.sockV4;
}
else if( inDstIP->type == mDNSAddrType_IPv6 )
{
struct sockaddr_in6 * sa6;
sa6 = (struct sockaddr_in6 *) &to;
sa6->sin6_len = sizeof( *sa6 );
sa6->sin6_family = AF_INET6;
sa6->sin6_port = inDstPort.NotAnInteger;
sa6->sin6_flowinfo = 0;
sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
sa6->sin6_scope_id = info ? info->scopeID : 0;
sock = info ? info->ss.sockV6 : inMDNS->p->unicastSS.sockV6;
}
else
{
dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__ );
err = mStatus_BadParamErr;
goto exit;
}
n = (int)( (mDNSu8 *) inEnd - (mDNSu8 *) inMsg );
if( !IsValidSocket( sock ) )
{
dpkt( kDebugLevelChatty - 1,
DEBUG_NAME "DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info );
err = mStatus_Invalid;
goto exit;
}
dpkt( kDebugLevelChatty,
DEBUG_NAME "SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info );
n = sendto( sock, (mDNSu8 *) inMsg, n, 0, (struct sockaddr *) &to, to.ss_len );
if( n < 0 )
{
err = errno_compat();
if( ( ( err == EHOSTDOWN ) || ( err == ENETDOWN ) || ( err == EHOSTUNREACH ) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP ) )
{
goto exit;
}
dmsg( kDebugLevelError, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
__ROUTINE__, info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, inDstIP, mDNSVal16( inDstPort ),
sock, err, (unsigned int) inMDNS->timenow );
if( err == 0 ) err = mStatus_UnknownErr;
goto exit;
}
err = mStatus_NoError;
exit:
return( err );
}
mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
TCPConnectionCallback callback, void *context, int *descriptor)
{
(void)dst; (void)dstport; (void)InterfaceID; (void)callback; (void)context; (void)descriptor; return(mStatus_UnsupportedErr);
}
mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
{
(void)sd; }
mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
{
(void)sd; (void)buf; (void)buflen; return(0);
}
mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
{
(void)sd; (void)msg; (void)len; return(0);
}
void mDNSPlatformLock( const mDNS * const inMDNS )
{
check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
#if ( DEBUG )
if( semTake( inMDNS->p->lock, 60 * sysClkRateGet() ) != OK )
{
dmsg( kDebugLevelTragic, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS->p->lock, taskIdSelf() );
debug_stack_trace(); semShow( inMDNS->p->lock, 1 ); taskSuspend( 0 ); }
#else
semTake( inMDNS->p->lock, WAIT_FOREVER );
#endif
}
void mDNSPlatformUnlock( const mDNS * const inMDNS )
{
check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
if( taskIdSelf() != inMDNS->p->taskID )
{
SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule );
}
semGive( inMDNS->p->lock );
}
mDNSu32 mDNSPlatformStrLen( const void *inSrc )
{
check( inSrc );
return( (mDNSu32) strlen( (const char *) inSrc ) );
}
void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
{
check( inSrc );
check( inDst );
strcpy( (char *) inDst, (const char*) inSrc );
}
void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
memcpy( inDst, inSrc, inSize );
}
mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
return( memcmp( inSrc, inDst, inSize ) == 0 );
}
void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
{
check( inDst );
memset( inDst, 0, inSize );
}
mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
{
void * mem;
check( inSize > 0 );
mem = malloc( inSize );
check( mem );
return( mem );
}
mDNSexport void mDNSPlatformMemFree( void *inMem )
{
check( inMem );
if( inMem ) free( inMem );
}
mDNSexport mDNSu32 mDNSPlatformRandomSeed( void )
{
return( tickGet() );
}
mDNSexport mStatus mDNSPlatformTimeInit( void )
{
return( mStatus_NoError );
}
mDNSs32 mDNSPlatformRawTime( void )
{
return( (mDNSs32) tickGet() );
}
mDNSexport mDNSs32 mDNSPlatformUTC( void )
{
return( (mDNSs32) time( NULL ) );
}
mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex )
{
NetworkInterfaceInfoVxWorks * i;
if( inIndex == (mDNSu32) -1 ) return( mDNSInterface_LocalOnly );
if( inIndex != 0 )
{
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
if( i->ifinfo.InterfaceID && ( i->scopeID == inIndex ) ) return( i->ifinfo.InterfaceID );
}
}
return( NULL );
}
mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID )
{
NetworkInterfaceInfoVxWorks * i;
if( inID == mDNSInterface_LocalOnly ) return( (mDNSu32) -1 );
if( inID )
{
for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
if( i ) return( i->scopeID );
}
return( 0 );
}
mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
{
NetworkInterfaceInfoVxWorks * i;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
if( i->ifinfo.InterfaceID && ( strcmp( i->ifinfo.ifname, inName ) == 0 ) )
{
*outID = (mDNSInterfaceID) i;
return( mStatus_NoError );
}
}
return( mStatus_NoSuchNameErr );
}
mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
{
NetworkInterfaceInfoVxWorks * i;
for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
if( !i ) return( mStatus_NoSuchNameErr );
outInfo->name = i->ifinfo.ifname;
outInfo->ip = i->ifinfo.ip;
return( mStatus_NoError );
}
#if ( MDNS_DEBUGMSGS > 0 )
mDNSexport void debugf_( const char *inFormat, ... )
{
char buffer[ 512 ];
va_list args;
va_start( args, inFormat );
mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
va_end( args );
dlog( kDebugLevelInfo, "%s\n", buffer );
}
#endif
#if ( MDNS_DEBUGMSGS > 1 )
mDNSexport void verbosedebugf_( const char *inFormat, ... )
{
char buffer[ 512 ];
va_list args;
va_start( args, inFormat );
mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
va_end( args );
dlog( kDebugLevelVerbose, "%s\n", buffer );
}
#endif
mDNSexport void LogMsg( const char *inFormat, ... )
{
#if ( DEBUG )
char buffer[ 512 ];
va_list args;
va_start( args, inFormat );
mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
va_end( args );
dlog( kDebugLevelWarning, "%s\n", buffer );
#else
DEBUG_UNUSED( inFormat );
#endif
}
#if ( DEBUG )
mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... )
{
char buffer[ 512 ];
va_list args;
va_start( args, inFormat );
mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
va_end( args );
if( inLevel >= gMDNSDebugOverrideLevel ) inLevel = kDebugLevelMax;
dlog( inLevel, "%s", buffer );
}
#endif
#if 0
#pragma mark -
#pragma mark == Interfaces ==
#endif
#if ( MDNS_ENABLE_PPP )
#define IsCompatibleInterface( IFA ) \
( ( ( IFA )->ifa_flags & IFF_UP ) && \
( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \
( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
#else
#define IsCompatibleInterface( IFA ) \
( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \
( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) )
#endif
#define IsLinkLocalSockAddr( SA ) \
( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
: IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
#define FamilyToString( X ) \
( ( ( X ) == AF_INET ) ? "AF_INET" : \
( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
"UNKNOWN" ) ) )
mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC )
{
mStatus err;
struct ifaddrs * ifaList;
struct ifaddrs * ifa;
int family;
mDNSBool foundV4;
mDNSBool foundV6;
struct ifaddrs * loopbackV4;
struct ifaddrs * loopbackV6;
mDNSEthAddr primaryMAC;
SocketRef infoSock;
char defaultName[ 64 ];
NetworkInterfaceInfoVxWorks * i;
domainlabel nicelabel;
domainlabel hostlabel;
domainlabel tmp;
ifaList = NULL;
foundV4 = mDNSfalse;
foundV6 = mDNSfalse;
loopbackV4 = NULL;
loopbackV6 = NULL;
primaryMAC = zeroEthAddr;
infoSock = socket( AF_INET6, SOCK_DGRAM, 0 );
check_translated_errno( IsValidSocket( infoSock ), errno_compat(), kUnknownErr );
err = getifaddrs( &ifaList );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
{
int flags;
family = ifa->ifa_addr->sa_family;
dmsg( kDebugLevelVerbose, DEBUG_NAME "%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__,
ifa->ifa_name, if_nametoindex( ifa->ifa_name ), ifa->ifa_flags, FamilyToString( family ), family );
if( family == AF_LINK )
{
struct sockaddr_dl * sdl;
sdl = (struct sockaddr_dl *) ifa->ifa_addr;
if( ( sdl->sdl_type == IFT_ETHER ) && ( sdl->sdl_alen == sizeof( primaryMAC ) &&
mDNSSameEthAddress( &primaryMAC, &zeroEthAddr ) ) )
{
memcpy( primaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6 );
}
}
if( !IsCompatibleInterface( ifa ) ) continue;
if( IsLinkLocalSockAddr( ifa->ifa_addr ) )
{
struct ifaddrs * ifaLL;
for( ifaLL = ifaList; ifaLL; ifaLL = ifaLL->ifa_next )
{
if( ifaLL->ifa_addr->sa_family != family ) continue;
if( !IsCompatibleInterface( ifaLL ) ) continue;
if( strcmp( ifaLL->ifa_name, ifa->ifa_name ) != 0 ) continue;
if( !IsLinkLocalSockAddr( ifaLL->ifa_addr ) ) break;
}
if( ifaLL )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %8s(%d) skipping link-local alias\n", __ROUTINE__,
ifa->ifa_name, if_nametoindex( ifa->ifa_name ) );
continue;
}
}
flags = 0;
if( ( family == AF_INET6 ) && IsValidSocket( infoSock ) )
{
struct sockaddr_in6 * sa6;
struct in6_ifreq ifr6;
sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
mDNSPlatformMemZero( &ifr6, sizeof( ifr6 ) );
strcpy( ifr6.ifr_name, ifa->ifa_name );
ifr6.ifr_addr = *sa6;
if( ioctl( infoSock, SIOCGIFAFLAG_IN6, (int) &ifr6 ) != -1 )
{
flags = ifr6.ifr_ifru.ifru_flags6;
}
}
if( flags & ( IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY ) )
{
dmsg( kDebugLevelNotice, DEBUG_NAME "%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__,
ifa->ifa_name, if_nametoindex( ifa->ifa_name ), flags );
continue;
}
if( ifa->ifa_flags & IFF_LOOPBACK )
{
if( family == AF_INET ) loopbackV4 = ifa;
else loopbackV6 = ifa;
}
else
{
if( ( family == AF_INET ) && gMDNSDeferIPv4 && IsLinkLocalSockAddr( ifa->ifa_addr ) ) continue;
i = AddInterfaceToList( inMDNS, ifa, inUTC );
if( i && i->multicast )
{
if( family == AF_INET ) foundV4 = mDNStrue;
else foundV6 = mDNStrue;
}
}
}
if( !foundV4 && loopbackV4 ) AddInterfaceToList( inMDNS, loopbackV4, inUTC );
if( !foundV6 && loopbackV6 ) AddInterfaceToList( inMDNS, loopbackV6, inUTC );
freeifaddrs( ifaList );
if( IsValidSocket( infoSock ) ) close_compat( infoSock );
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
if( i->exists )
{
mDNSBool txrx;
txrx = i->multicast && ( ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) || !FindRoutableIPv4( inMDNS, i->scopeID ) );
if( i->ifinfo.McastTxRx != txrx )
{
i->ifinfo.McastTxRx = txrx;
i->exists = 2; }
}
}
mDNS_snprintf( defaultName, sizeof( defaultName ), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
primaryMAC.b[ 0 ], primaryMAC.b[ 1 ], primaryMAC.b[ 2 ], primaryMAC.b[ 3 ], primaryMAC.b[ 4 ], primaryMAC.b[ 5 ] );
MakeDomainLabelFromLiteralString( &nicelabel, "Put Nice Name Here" ); if( nicelabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel, defaultName );
MakeDomainLabelFromLiteralString( &tmp, "Put-DNS-Name-Here" ); ConvertUTF8PstringToRFC1034HostLabel( tmp.c, &hostlabel );
if( hostlabel.c[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel.c, &hostlabel );
if( hostlabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel, defaultName );
if( !SameDomainLabelCS( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "Updating nicelabel to \"%#s\"\n", nicelabel.c );
inMDNS->p->userNiceLabel = nicelabel;
inMDNS->nicelabel = nicelabel;
}
if( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "Updating hostlabel to \"%#s\"\n", hostlabel.c );
inMDNS->p->userHostLabel = hostlabel;
inMDNS->hostlabel = hostlabel;
mDNS_SetFQDN( inMDNS );
}
return( mStatus_NoError );
}
mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC )
{
mStatus err;
mDNSAddr ip;
mDNSAddr mask;
mDNSu32 scopeID;
NetworkInterfaceInfoVxWorks ** p;
NetworkInterfaceInfoVxWorks * i;
i = NULL;
err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ip );
require_noerr( err, exit );
err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &mask );
require_noerr( err, exit );
scopeID = if_nametoindex( inIFA->ifa_name );
check( scopeID );
for( p = &inMDNS->p->interfaceList; *p; p = &( *p )->next )
{
if( ( scopeID == ( *p )->scopeID ) && mDNSSameAddress( &ip, &( *p )->ifinfo.ip ) )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__,
scopeID, &ip, *p );
( *p )->exists = mDNStrue;
i = *p;
goto exit;
}
}
i = (NetworkInterfaceInfoVxWorks *) calloc( 1, sizeof( *i ) );
require( i, exit );
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__, scopeID, &ip, i );
strncpy( i->ifinfo.ifname, inIFA->ifa_name, sizeof( i->ifinfo.ifname ) );
i->ifinfo.ifname[ sizeof( i->ifinfo.ifname ) - 1 ] = '\0';
i->ifinfo.InterfaceID = NULL;
i->ifinfo.ip = ip;
i->ifinfo.mask = mask;
i->ifinfo.Advertise = inMDNS->AdvertiseLocalAddresses;
i->ifinfo.McastTxRx = mDNSfalse;
i->next = NULL;
i->exists = mDNStrue;
i->lastSeen = inUTC;
i->scopeID = scopeID;
i->family = inIFA->ifa_addr->sa_family;
i->multicast = ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTOPOINT );
i->ss.info = i;
i->ss.sockV4 = kInvalidSocketRef;
i->ss.sockV6 = kInvalidSocketRef;
*p = i;
exit:
return( i );
}
#define mDNSAddressIsNonLinkLocalIPv4( X ) \
( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC )
{
int count;
NetworkInterfaceInfoVxWorks * i;
count = 0;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
NetworkInterfaceInfo * n;
NetworkInterfaceInfoVxWorks * primary;
if( !i->exists ) continue;
n = &i->ifinfo;
primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
if( !primary )
{
dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! didn't find %s(%u)\n", __ROUTINE__, i->ifinfo.ifname, i->scopeID );
continue;
}
if( n->InterfaceID && ( n->InterfaceID != (mDNSInterfaceID) primary ) )
{
dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__,
n->InterfaceID, primary );
n->InterfaceID = NULL;
}
if( !n->InterfaceID )
{
mDNSBool flapping;
n->InterfaceID = (mDNSInterfaceID) primary;
flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 );
mDNS_RegisterInterface( inMDNS, n, flapping );
if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__,
i->ifinfo.ifname, i->scopeID, primary, &n->ip,
flapping ? " (Flapping)" : "",
n->InterfaceActive ? " (Primary)" : "" );
}
if( n->McastTxRx )
{
mStatus err;
if( ( ( i->family == AF_INET ) && !IsValidSocket( primary->ss.sockV4 ) ) ||
( ( i->family == AF_INET6 ) && !IsValidSocket( primary->ss.sockV6 ) ) )
{
err = SetupSocket( inMDNS, &i->ifinfo.ip, mDNStrue, i->family, &primary->ss );
check_noerr( err );
}
}
else
{
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__,
i->ifinfo.ifname, i->scopeID, primary, &n->ip );
}
}
return( count );
}
mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC )
{
NetworkInterfaceInfoVxWorks * i;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
if( !i->exists ) continue;
i->lastSeen = inUTC;
i->exists = mDNSfalse;
}
}
mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing )
{
int count;
NetworkInterfaceInfoVxWorks * i;
NetworkInterfaceInfoVxWorks ** p;
count = 0;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
NetworkInterfaceInfoVxWorks * primary;
if( !i->ifinfo.InterfaceID ) continue;
primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
if( ( i->exists == 0 ) || ( i->exists == 2 ) || ( i->ifinfo.InterfaceID != (mDNSInterfaceID) primary ) )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__,
i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
i->ifinfo.InterfaceActive ? " (Primary)" : "" );
mDNS_DeregisterInterface( inMDNS, &i->ifinfo, mDNSfalse );
i->ifinfo.InterfaceID = NULL;
if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
}
}
p = &inMDNS->p->interfaceList;
while( *p )
{
i = *p;
ForgetSocket( &i->ss.sockV4 );
ForgetSocket( &i->ss.sockV6 );
if( !i->exists )
{
mDNSBool deleteIt;
if( inClosing )
{
check_string( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0, "closing with in-use records!" );
deleteIt = mDNStrue;
}
else
{
if( i->lastSeen == inUTC ) i->lastSeen = inUTC - 1;
deleteIt = ( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0 ) && ( ( inUTC - i->lastSeen ) >= 60 );
}
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__,
deleteIt ? "Deleting" : "Holding", i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
inUTC - i->lastSeen, i->ifinfo.InterfaceActive ? " (Primary)" : "" );
if( deleteIt )
{
*p = i->next;
free( i );
continue;
}
}
p = &i->next;
}
return( count );
}
mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID )
{
#if ( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
NetworkInterfaceInfoVxWorks * i;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
if( i->exists && ( i->scopeID == inScopeID ) && mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) )
{
break;
}
}
return( i );
#else
DEBUG_UNUSED( inMDNS );
DEBUG_UNUSED( inScopeID );
return( NULL );
#endif
}
mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex )
{
NetworkInterfaceInfoVxWorks * i;
check( inIndex != 0 );
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
if( i->exists && ( i->scopeID == inIndex ) &&
( MDNS_AAAA_OVER_IPV4 ||
( ( inFamily == AF_INET ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) ) ||
( ( inFamily == AF_INET6 ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv6 ) ) ) )
{
return( i );
}
}
return( NULL );
}
mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS )
{
mStatus err;
SocketRef * sockPtr;
mDNSIPPort port;
SocketRef sock;
const int on = 1;
check( inAddr );
check( inSS );
sockPtr = ( inFamily == AF_INET ) ? &inSS->sockV4 : &inSS->sockV6;
port = ( inMcast || inMDNS->CanReceiveUnicastOn5353 ) ? MulticastDNSPort : zeroIPPort;
sock = socket( inFamily, SOCK_DGRAM, IPPROTO_UDP );
err = translate_errno( IsValidSocket( sock ), errno_compat(), mStatus_UnknownErr );
require_noerr( err, exit );
if( port.NotAnInteger )
{
err = setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof( on ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
}
if( inFamily == AF_INET )
{
const int ttlV4 = 255;
const u_char ttlV4Mcast = 255;
struct sockaddr_in sa4;
err = setsockopt( sock, IPPROTO_IP, IP_RECVDSTADDR, (char *) &on, sizeof( on ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IP, IP_RECVIF, (char *) &on, sizeof( on ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
if( inMcast )
{
struct in_addr addrV4;
struct ip_mreq mreqV4;
addrV4.s_addr = inAddr->ip.v4.NotAnInteger;
mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
mreqV4.imr_interface = addrV4;
err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqV4, sizeof( mreqV4 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addrV4, sizeof( addrV4 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
}
err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &ttlV4, sizeof( ttlV4 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttlV4Mcast, sizeof( ttlV4Mcast ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
sa4.sin_len = sizeof( sa4 );
sa4.sin_family = AF_INET;
sa4.sin_port = port.NotAnInteger;
sa4.sin_addr.s_addr = htonl( INADDR_ANY ); err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
}
else if( inFamily == AF_INET6 )
{
struct sockaddr_in6 sa6;
const int ttlV6 = 255;
err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &on, sizeof( on ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof( on ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
if( inMcast )
{
u_int ifindex;
struct ipv6_mreq mreqV6;
ifindex = inSS->info->scopeID;
mreqV6.ipv6mr_interface = ifindex;
mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroup_v6.ip.v6 );
err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqV6, sizeof( mreqV6 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &ifindex, sizeof( ifindex ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
}
err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &on, sizeof( on ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
sa6.sin6_len = sizeof( sa6 );
sa6.sin6_family = AF_INET6;
sa6.sin6_port = port.NotAnInteger;
sa6.sin6_flowinfo = 0;
sa6.sin6_addr = in6addr_any; sa6.sin6_scope_id = 0;
err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
}
else
{
dmsg( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inFamily );
err = kUnsupportedErr;
goto exit;
}
err = ioctl( sock, FIONBIO, (int) &on );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
*sockPtr = sock;
sock = kInvalidSocketRef;
err = mStatus_NoError;
exit:
if( IsValidSocket( sock ) ) close_compat( sock );
return( err );
}
mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP )
{
mStatus err;
check( inSA );
check( outIP );
if( inSA->sa_family == AF_INET )
{
struct sockaddr_in * sa4;
sa4 = (struct sockaddr_in *) inSA;
outIP->type = mDNSAddrType_IPv4;
outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
err = mStatus_NoError;
}
else if( inSA->sa_family == AF_INET6 )
{
struct sockaddr_in6 * sa6;
sa6 = (struct sockaddr_in6 *) inSA;
outIP->type = mDNSAddrType_IPv6;
outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) ) outIP->ip.v6.w[ 1 ] = 0;
err = mStatus_NoError;
}
else
{
dmsg( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family (%d)\n", __ROUTINE__, inSA->sa_family );
err = mStatus_BadParamErr;
}
return( err );
}
#if 0
#pragma mark -
#pragma mark == Commands ==
#endif
mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS )
{
mStatus err;
err = pipeDevCreate( "/pipe/mDNS", 32, 1 );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
inMDNS->p->commandPipe = open( "/pipe/mDNS", O_RDWR, 0 );
err = translate_errno( inMDNS->p->commandPipe != ERROR, errno_compat(), mStatus_UnsupportedErr );
require_noerr( err, exit );
exit:
return( err );
}
mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS )
{
mStatus err;
if( inMDNS->p->commandPipe != ERROR )
{
err = close( inMDNS->p->commandPipe );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
inMDNS->p->commandPipe = ERROR;
err = pipeDevDelete( "/pipe/mDNS", FALSE );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
}
return( mStatus_NoError );
}
mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode )
{
mStatus err;
require_action_quiet( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) );
err = translate_errno( err >= 0, errno_compat(), kWriteErr );
require_noerr( err, exit );
exit:
return( err );
}
mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS )
{
mStatus err;
MDNSPipeCommandCode cmd;
mDNSs32 utc;
err = read( inMDNS->p->commandPipe, &cmd, sizeof( cmd ) );
err = translate_errno( err >= 0, errno_compat(), kReadErr );
require_noerr( err, exit );
switch( cmd )
{
case kMDNSPipeCommandCodeReschedule: break;
case kMDNSPipeCommandCodeReconfigure: dmsg( kDebugLevelInfo, DEBUG_NAME "*** NETWORK CONFIGURATION CHANGE ***\n" );
mDNSPlatformLock( inMDNS );
utc = mDNSPlatformUTC();
MarkAllInterfacesInactive( inMDNS, utc );
UpdateInterfaceList( inMDNS, utc );
ClearInactiveInterfaces( inMDNS, utc, mDNSfalse );
SetupActiveInterfaces( inMDNS, utc );
mDNSPlatformUnlock( inMDNS );
mDNS_ConfigChanged(inMDNS);
break;
case kMDNSPipeCommandCodeQuit: inMDNS->p->quit = mDNStrue;
break;
default:
dmsg( kDebugLevelError, DEBUG_NAME "unknown pipe command (%d)\n", cmd );
err = mStatus_BadParamErr;
goto exit;
}
exit:
return( err );
}
#if 0
#pragma mark -
#pragma mark == Threads ==
#endif
mDNSlocal void Task( mDNS *inMDNS )
{
mStatus err;
mDNSs32 nextEvent;
fd_set readSet;
int maxFd;
struct timeval timeout;
NetworkInterfaceInfoVxWorks * i;
int fd;
int n;
check( inMDNS );
err = TaskInit( inMDNS );
require_noerr( err, exit );
while( !inMDNS->p->quit )
{
nextEvent = mDNS_Execute( inMDNS );
TaskSetupSelect( inMDNS, &readSet, &maxFd, nextEvent, &timeout );
n = select( maxFd + 1, &readSet, NULL, NULL, &timeout );
check_translated_errno( n >= 0, errno_compat(), kUnknownErr );
if( n == 0 ) continue;
n = 0;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
fd = i->ss.sockV4;
if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
{
TaskProcessPackets( inMDNS, &i->ss, fd );
++n;
}
fd = i->ss.sockV6;
if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
{
TaskProcessPackets( inMDNS, &i->ss, fd );
++n;
}
}
fd = inMDNS->p->unicastSS.sockV4;
if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
{
TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
++n;
}
fd = inMDNS->p->unicastSS.sockV6;
if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
{
TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
++n;
}
fd = inMDNS->p->commandPipe;
check( fd >= 0 );
if( FD_ISSET( fd, &readSet ) )
{
ProcessCommand( inMDNS );
++n;
}
check_string( n > 0, "select said something was readable, but nothing was" );
}
exit:
TaskTerm( inMDNS );
}
mDNSlocal mStatus TaskInit( mDNS *inMDNS )
{
mStatus err;
mDNSs32 utc;
socklen_t len;
inMDNS->p->taskID = taskIdSelf();
err = SetupCommandPipe( inMDNS );
require_noerr( err, exit );
inMDNS->CanReceiveUnicastOn5353 = mDNStrue;
inMDNS->HIHardware.c[ 0 ] = 11;
memcpy( &inMDNS->HIHardware.c[ 1 ], "Device V1.0", inMDNS->HIHardware.c[ 0 ] );
err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET, &inMDNS->p->unicastSS );
check_noerr( err );
if( err == mStatus_NoError )
{
struct sockaddr_in sa4;
len = sizeof( sa4 );
err = getsockname( inMDNS->p->unicastSS.sockV4, (struct sockaddr *) &sa4, &len );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
if( err == 0 ) inMDNS->UnicastPort4.NotAnInteger = sa4.sin_port;
}
err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET6, &inMDNS->p->unicastSS );
check_noerr( err );
if( err == mStatus_NoError )
{
struct sockaddr_in6 sa6;
len = sizeof( sa6 );
err = getsockname( inMDNS->p->unicastSS.sockV6, (struct sockaddr *) &sa6, &len );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
if( err == 0 ) inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port;
}
utc = mDNSPlatformUTC();
UpdateInterfaceList( inMDNS, utc );
SetupActiveInterfaces( inMDNS, utc );
err = mStatus_NoError;
exit:
inMDNS->p->initErr = err;
semGive( inMDNS->p->initEvent );
return( err );
}
mDNSlocal void TaskTerm( mDNS *inMDNS )
{
mStatus err;
mDNSs32 utc;
utc = mDNSPlatformUTC();
MarkAllInterfacesInactive( inMDNS, utc );
ClearInactiveInterfaces( inMDNS, utc, mDNStrue );
check_string( !inMDNS->p->interfaceList, "LEAK: closing without deleting all interfaces" );
ForgetSocket( &inMDNS->p->unicastSS.sockV4);
ForgetSocket( &inMDNS->p->unicastSS.sockV6 );
err = TearDownCommandPipe( inMDNS );
check_noerr( err );
err = semGive( inMDNS->p->quitEvent );
check_translated_errno( err == 0, errno_compat(), kUnknownErr );
}
mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout )
{
NetworkInterfaceInfoVxWorks * i;
int maxFd;
int fd;
mDNSs32 delta;
FD_ZERO( outSet );
maxFd = -1;
for( i = inMDNS->p->interfaceList; i; i = i->next )
{
fd = i->ss.sockV4;
if( IsValidSocket( fd ) )
{
FD_SET( fd, outSet );
if( fd > maxFd ) maxFd = fd;
}
fd = i->ss.sockV6;
if( IsValidSocket( fd ) )
{
FD_SET( fd, outSet );
if( fd > maxFd ) maxFd = fd;
}
}
fd = inMDNS->p->unicastSS.sockV4;
if( IsValidSocket( fd ) )
{
FD_SET( fd, outSet );
if( fd > maxFd ) maxFd = fd;
}
fd = inMDNS->p->unicastSS.sockV6;
if( IsValidSocket( fd ) )
{
FD_SET( fd, outSet );
if( fd > maxFd ) maxFd = fd;
}
fd = inMDNS->p->commandPipe;
check( fd >= 0 );
FD_SET( fd, outSet );
if( fd > maxFd ) maxFd = fd;
check( maxFd > 0 );
*outMaxFd = maxFd;
delta = inNextEvent - mDNS_TimeNow( inMDNS );
if( delta <= 0 )
{
outTimeout->tv_sec = 0;
outTimeout->tv_usec = 0;
}
else
{
outTimeout->tv_sec = delta / mDNSPlatformOneSecond;
outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicro;
if( outTimeout->tv_usec >= 1000000L )
{
outTimeout->tv_sec += 1;
outTimeout->tv_usec = 0;
}
}
}
mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock )
{
mDNSu32 ifindex;
ssize_t n;
mDNSu8 * buf;
size_t size;
struct sockaddr_storage from;
size_t fromSize;
mDNSAddr destAddr;
mDNSAddr senderAddr;
mDNSIPPort senderPort;
mDNSInterfaceID id;
buf = (mDNSu8 *) &inMDNS->imsg;
size = sizeof( inMDNS->imsg );
for( ;; )
{
ifindex = 0;
n = mDNSRecvMsg( inSock, buf, size, &from, sizeof( from ), &fromSize, &destAddr, &ifindex );
if( n < 0 ) break;
if( from.ss_family == AF_INET )
{
struct sockaddr_in * sa4;
sa4 = (struct sockaddr_in *) &from;
senderAddr.type = mDNSAddrType_IPv4;
senderAddr.ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
senderPort.NotAnInteger = sa4->sin_port;
}
else if( from.ss_family == AF_INET6 )
{
struct sockaddr_in6 * sa6;
sa6 = (struct sockaddr_in6 *) &from;
senderAddr.type = mDNSAddrType_IPv6;
senderAddr.ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
senderPort.NotAnInteger = sa6->sin6_port;
}
else
{
dmsg( kDebugLevelWarning, DEBUG_NAME "%s: WARNING! from addr unknown family %d\n", __ROUTINE__, from.ss_family );
continue;
}
if( mDNSAddrIsDNSMulticast( &destAddr ) )
{
if( !inSS->info || !inSS->info->exists )
{
dpkt( kDebugLevelChatty - 3, DEBUG_NAME " ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
&senderAddr, &destAddr, inSock );
continue;
}
if( ifindex != inSS->info->scopeID )
{
#if ( DEBUG && MDNS_DEBUG_PACKETS )
char ifname[ IF_NAMESIZE ];
#endif
dpkt( kDebugLevelChatty - 3,
DEBUG_NAME " ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n",
&senderAddr, &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID,
if_indextoname( ifindex, ifname ), ifindex );
continue;
}
id = inSS->info->ifinfo.InterfaceID;
dpkt( kDebugLevelChatty - 2, DEBUG_NAME "recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n",
n, &senderAddr, mDNSVal16( senderPort ), &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID, id );
}
else
{
NetworkInterfaceInfoVxWorks * i;
for( i = inMDNS->p->interfaceList; i && ( i->scopeID != ifindex ); i = i->next ) {}
if( i ) id = i->ifinfo.InterfaceID;
else id = NULL;
}
mDNSCoreReceive( inMDNS, buf, buf + n, &senderAddr, senderPort, &destAddr, MulticastDNSPort, id );
}
}
mDNSlocal ssize_t
mDNSRecvMsg(
SocketRef inSock,
void * inBuffer,
size_t inBufferSize,
void * outFrom,
size_t inFromSize,
size_t * outFromSize,
mDNSAddr * outDstAddr,
uint32_t * outIndex )
{
struct msghdr msg;
struct iovec iov;
ssize_t n;
char ancillary[ 1024 ];
struct cmsghdr * cmPtr;
int err;
iov.iov_base = (char *) inBuffer;
iov.iov_len = inBufferSize;
msg.msg_name = (caddr_t) outFrom;
msg.msg_namelen = inFromSize;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t) &ancillary;
msg.msg_controllen = sizeof( ancillary );
msg.msg_flags = 0;
n = recvmsg( inSock, &msg, 0 );
if( n < 0 )
{
err = errno_compat();
if( err != EWOULDBLOCK ) dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) returned %d, errno %d\n",
__ROUTINE__, inSock, n, err );
goto exit;
}
if( msg.msg_controllen < sizeof( struct cmsghdr ) )
{
dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
__ROUTINE__, inSock, msg.msg_controllen, sizeof( struct cmsghdr ) );
n = mStatus_UnknownErr;
goto exit;
}
if( msg.msg_flags & MSG_CTRUNC )
{
dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__, inSock, n );
n = mStatus_BadFlagsErr;
goto exit;
}
*outFromSize = msg.msg_namelen;
for( cmPtr = CMSG_FIRSTHDR( &msg ); cmPtr; cmPtr = CMSG_NXTHDR( &msg, cmPtr ) )
{
if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVDSTADDR ) )
{
outDstAddr->type = mDNSAddrType_IPv4;
outDstAddr->ip.v4.NotAnInteger = *( (mDNSu32 *) CMSG_DATA( cmPtr ) );
}
else if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVIF ) )
{
struct sockaddr_dl * sdl;
sdl = (struct sockaddr_dl *) CMSG_DATA( cmPtr );
*outIndex = sdl->sdl_index;
}
else if( ( cmPtr->cmsg_level == IPPROTO_IPV6 ) && ( cmPtr->cmsg_type == IPV6_PKTINFO ) )
{
struct in6_pktinfo * pi6;
pi6 = (struct in6_pktinfo *) CMSG_DATA( cmPtr );
outDstAddr->type = mDNSAddrType_IPv6;
outDstAddr->ip.v6 = *( (mDNSv6Addr *) &pi6->ipi6_addr );
*outIndex = pi6->ipi6_ifindex;
}
}
exit:
return( n );
}
#if 0
#pragma mark -
#pragma mark == Debugging ==
#endif
#if ( DEBUG && MDNS_DEBUG_SHOW )
void mDNSShow( void );
void mDNSShow( void )
{
NetworkInterfaceInfoVxWorks * i;
int num;
AuthRecord * r;
mDNSs32 utc;
dmsg( kDebugLevelMax, "\n-- mDNS globals --\n" );
dmsg( kDebugLevelMax, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS ) );
dmsg( kDebugLevelMax, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord ) );
dmsg( kDebugLevelMax, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord ) );
dmsg( kDebugLevelMax, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord ) );
dmsg( kDebugLevelMax, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond );
dmsg( kDebugLevelMax, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro );
dmsg( kDebugLevelMax, " gMDNSPtr = %#p\n", gMDNSPtr );
if( !gMDNSPtr )
{
dmsg( kDebugLevelMax, "### mDNS not initialized\n" );
return;
}
dmsg( kDebugLevelMax, " nicelabel = \"%#s\"\n", gMDNSPtr->nicelabel.c );
dmsg( kDebugLevelMax, " hostLabel = \"%#s\"\n", gMDNSPtr->hostlabel.c );
dmsg( kDebugLevelMax, " MulticastHostname = \"%##s\"\n", gMDNSPtr->MulticastHostname.c );
dmsg( kDebugLevelMax, " HIHardware = \"%#s\"\n", gMDNSPtr->HIHardware.c );
dmsg( kDebugLevelMax, " HISoftware = \"%#s\"\n", gMDNSPtr->HISoftware.c );
dmsg( kDebugLevelMax, " UnicastPort4/6 = %d/%d\n",
mDNSVal16( gMDNSPtr->UnicastPort4 ), mDNSVal16( gMDNSPtr->UnicastPort6 ) );
dmsg( kDebugLevelMax, " unicastSS.sockV4/V6 = %d/%d\n",
gMDNSPtr->p->unicastSS.sockV4, gMDNSPtr->p->unicastSS.sockV6 );
dmsg( kDebugLevelMax, " lock = %#p\n", gMDNSPtr->p->lock );
dmsg( kDebugLevelMax, " initEvent = %#p\n", gMDNSPtr->p->initEvent );
dmsg( kDebugLevelMax, " initErr = %ld\n", gMDNSPtr->p->initErr );
dmsg( kDebugLevelMax, " quitEvent = %#p\n", gMDNSPtr->p->quitEvent );
dmsg( kDebugLevelMax, " commandPipe = %d\n", gMDNSPtr->p->commandPipe );
dmsg( kDebugLevelMax, " taskID = %#p\n", gMDNSPtr->p->taskID );
dmsg( kDebugLevelMax, "\n" );
utc = mDNSPlatformUTC();
dmsg( kDebugLevelMax, "-- mDNS interfaces --\n" );
num = 0;
for( i = gMDNSPtr->p->interfaceList; i; i = i->next )
{
dmsg( kDebugLevelMax, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
num, i->ifinfo.ifname, i->scopeID, &i->ifinfo.ip,
i->ifinfo.InterfaceID ? " REGISTERED" : "*NOT* registered",
i->ss.sockV4, i->ss.sockV6, utc - i->lastSeen );
++num;
}
dmsg( kDebugLevelMax, "\n" );
dmsg( kDebugLevelMax, "-- mDNS resource records --\n" );
num = 0;
for( r = gMDNSPtr->ResourceRecords; r; r = r->next )
{
i = (NetworkInterfaceInfoVxWorks *) r->resrec.InterfaceID;
if( r->resrec.rrtype == kDNSType_TXT )
{
RDataBody * rd;
const mDNSu8 * txt;
const mDNSu8 * end;
mDNSu8 size;
int nEntries;
rd = &r->resrec.rdata->u;
dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num, i,
i ? i->ifinfo.ifname : "<any>",
i ? i->scopeID : 0,
r->resrec.rdlength, r->resrec.name->c, DNSTypeName( r->resrec.rrtype ) );
nEntries = 0;
txt = rd->txt.c;
end = txt + r->resrec.rdlength;
while( txt < end )
{
size = *txt++;
if( ( txt + size ) > end )
{
dmsg( kDebugLevelMax, " ### ERROR! txt length byte too big (%u, %u max)\n", size, end - txt );
break;
}
dmsg( kDebugLevelMax, " string %2d (%3d bytes): \"%.*s\"\n", nEntries, size, size, txt );
txt += size;
++nEntries;
}
}
else
{
dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %s\n", num, i,
i ? i->ifinfo.ifname : "<any>",
i ? i->scopeID : 0,
ARDisplayString( gMDNSPtr, r ) );
}
++num;
}
dmsg( kDebugLevelMax, "\n");
}
#endif // DEBUG && MDNS_DEBUG_SHOW