2 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: mDNSVxWorks.c,v $
26 Revision 1.28 2005/05/30 07:36:38 bradley
27 New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
32 #pragma mark == Configuration ==
35 //===========================================================================================================================
37 //===========================================================================================================================
39 #define DEBUG_NAME "[mDNS] "
40 #define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
41 #define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
42 #define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
43 #define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough.
44 #define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines.
45 #define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details).
57 #include <sys/types.h>
59 #include <arpa/inet.h>
61 #include <net/if_dl.h>
62 #include <net/if_types.h>
63 #include <net/ifaddrs.h>
64 #include <netinet6/in6_var.h>
65 #include <netinet/if_ether.h>
66 #include <netinet/in.h>
67 #include <netinet/ip.h>
68 #include <sys/ioctl.h>
69 #include <sys/socket.h>
75 #include "selectLib.h"
82 #include "CommonServices.h"
83 #include "DebugServices.h"
84 #include "DNSCommon.h"
85 #include "mDNSEmbeddedAPI.h"
87 #include "mDNSVxWorks.h"
90 #pragma mark == Constants ==
93 //===========================================================================================================================
95 //===========================================================================================================================
97 typedef uint8_t MDNSPipeCommandCode
;
99 #define kMDNSPipeCommandCodeInvalid 0
100 #define kMDNSPipeCommandCodeReschedule 1
101 #define kMDNSPipeCommandCodeReconfigure 2
102 #define kMDNSPipeCommandCodeQuit 3
105 #pragma mark == Prototypes ==
108 //===========================================================================================================================
110 //===========================================================================================================================
113 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... );
115 #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
117 #define dmsg( LEVEL, ARGS... )
120 #if( DEBUG && MDNS_DEBUG_PACKETS )
121 #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
123 #define dpkt( LEVEL, ARGS... )
126 #define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
127 #define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
131 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
);
132 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
);
133 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
);
134 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
);
135 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
);
136 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
);
137 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
);
138 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
);
139 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
);
143 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
144 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
145 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
146 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
150 mDNSlocal
void Task( mDNS
*inMDNS
);
151 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
152 mDNSlocal
void TaskTerm( mDNS
*inMDNS
);
153 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
);
154 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
);
162 size_t * outFromSize
,
163 mDNSAddr
* outDstAddr
,
164 uint32_t * outIndex
);
166 // DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
172 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
173 struct mDNSPlatformInterfaceInfo
179 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
180 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
187 #pragma mark == Globals ==
190 //===========================================================================================================================
192 //===========================================================================================================================
194 debug_log_new_default_category( mdns
);
196 mDNSexport mDNSs32 mDNSPlatformOneSecond
;
197 mDNSlocal mDNSs32 gMDNSTicksToMicro
= 0;
198 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
199 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
200 mDNSlocal mDNSBool gMDNSDeferIPv4
= mDNSfalse
;
202 DebugLevel gMDNSDebugOverrideLevel
= kDebugLevelMax
;
209 //===========================================================================================================================
211 //===========================================================================================================================
213 void mDNSReconfigure( void )
215 if( gMDNSPtr
) SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
218 //===========================================================================================================================
220 //===========================================================================================================================
222 void mDNSDeferIPv4( mDNSBool inDefer
)
224 gMDNSDeferIPv4
= inDefer
;
231 //===========================================================================================================================
233 //===========================================================================================================================
235 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
240 mDNSPlatformOneSecond
= sysClkRateGet();
241 gMDNSTicksToMicro
= ( 1000000L / mDNSPlatformOneSecond
);
243 // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
245 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
246 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
247 inMDNS
->p
->unicastSS
.info
= NULL
;
248 inMDNS
->p
->unicastSS
.sockV4
= kInvalidSocketRef
;
249 inMDNS
->p
->unicastSS
.sockV6
= kInvalidSocketRef
;
250 inMDNS
->p
->initErr
= mStatus_NotInitializedErr
;
251 inMDNS
->p
->commandPipe
= ERROR
;
252 inMDNS
->p
->taskID
= ERROR
;
254 inMDNS
->p
->lock
= semMCreate( SEM_Q_FIFO
);
255 require_action( inMDNS
->p
->lock
, exit
, err
= mStatus_NoMemoryErr
);
257 inMDNS
->p
->initEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
258 require_action( inMDNS
->p
->initEvent
, exit
, err
= mStatus_NoMemoryErr
);
260 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
261 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
263 // Start the task and wait for it to initialize. The task does the full initialization from its own context
264 // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers).
265 // We wait here until the init is complete because it needs to be ready to use as soon as this function returns.
267 id
= taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR
) Task
, (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
268 err
= translate_errno( id
!= ERROR
, errno_compat(), mStatus_NoMemoryErr
);
269 require_noerr( err
, exit
);
271 err
= semTake( inMDNS
->p
->initEvent
, WAIT_FOREVER
);
272 if( err
== OK
) err
= inMDNS
->p
->initErr
;
273 require_noerr( err
, exit
);
276 mDNSCoreInitComplete( inMDNS
, err
);
279 if( err
) mDNSPlatformClose( inMDNS
);
283 //===========================================================================================================================
285 //===========================================================================================================================
287 void mDNSPlatformClose( mDNS
* const inMDNS
)
295 // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread.
297 if( inMDNS
->p
->taskID
!= ERROR
)
299 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
300 if( inMDNS
->p
->quitEvent
)
302 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
305 inMDNS
->p
->taskID
= ERROR
;
308 // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
310 ForgetSem( &inMDNS
->p
->quitEvent
);
311 ForgetSem( &inMDNS
->p
->initEvent
);
312 ForgetSem( &inMDNS
->p
->lock
);
314 dmsg( kDebugLevelNotice
, DEBUG_NAME
"CLOSED\n" );
317 //===========================================================================================================================
318 // mDNSPlatformSendUDP
319 //===========================================================================================================================
323 const mDNS
* const inMDNS
,
324 const void * const inMsg
,
325 const mDNSu8
* const inEnd
,
326 mDNSInterfaceID inInterfaceID
,
327 const mDNSAddr
* inDstIP
,
328 mDNSIPPort inDstPort
)
331 NetworkInterfaceInfoVxWorks
* info
;
333 struct sockaddr_storage to
;
336 // Set up the sockaddr to sent to and the socket to send on.
338 info
= (NetworkInterfaceInfoVxWorks
*) inInterfaceID
;
339 if( inDstIP
->type
== mDNSAddrType_IPv4
)
341 struct sockaddr_in
* sa4
;
343 sa4
= (struct sockaddr_in
*) &to
;
344 sa4
->sin_len
= sizeof( *sa4
);
345 sa4
->sin_family
= AF_INET
;
346 sa4
->sin_port
= inDstPort
.NotAnInteger
;
347 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
348 sock
= info
? info
->ss
.sockV4
: inMDNS
->p
->unicastSS
.sockV4
;
350 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
352 struct sockaddr_in6
* sa6
;
354 sa6
= (struct sockaddr_in6
*) &to
;
355 sa6
->sin6_len
= sizeof( *sa6
);
356 sa6
->sin6_family
= AF_INET6
;
357 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
358 sa6
->sin6_flowinfo
= 0;
359 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
360 sa6
->sin6_scope_id
= info
? info
->scopeID
: 0;
361 sock
= info
? info
->ss
.sockV6
: inMDNS
->p
->unicastSS
.sockV6
;
365 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__
);
366 err
= mStatus_BadParamErr
;
370 // Send the packet if we've got a valid socket of this type. Note: mDNSCore may ask us to send an IPv4 packet and then
371 // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error.
373 n
= (int)( (mDNSu8
*) inEnd
- (mDNSu8
*) inMsg
);
374 if( !IsValidSocket( sock
) )
376 dpkt( kDebugLevelChatty
- 1,
377 DEBUG_NAME
"DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
378 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
379 err
= mStatus_Invalid
;
383 dpkt( kDebugLevelChatty
,
384 DEBUG_NAME
"SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
385 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
387 n
= sendto( sock
, (mDNSu8
*) inMsg
, n
, 0, (struct sockaddr
*) &to
, to
.ss_len
);
390 // Don't warn about ARP failures or no route to host for unicast destinations.
392 err
= errno_compat();
393 if( ( ( err
== EHOSTDOWN
) || ( err
== ENETDOWN
) || ( err
== EHOSTUNREACH
) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP
) )
398 dmsg( kDebugLevelError
, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
399 __ROUTINE__
, info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, inDstIP
, mDNSVal16( inDstPort
),
400 sock
, err
, (unsigned int) inMDNS
->timenow
);
401 if( err
== 0 ) err
= mStatus_UnknownErr
;
404 err
= mStatus_NoError
;
410 //===========================================================================================================================
411 // Connection-oriented (TCP) functions
412 //===========================================================================================================================
414 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
415 TCPConnectionCallback callback
, void *context
, int *descriptor
)
418 (void)dstport
; // Unused
419 (void)InterfaceID
; // Unused
420 (void)callback
; // Unused
421 (void)context
; // Unused
422 (void)descriptor
; // Unused
423 return(mStatus_UnsupportedErr
);
426 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
431 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
435 (void)buflen
; // Unused
439 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
447 //===========================================================================================================================
449 //===========================================================================================================================
451 void mDNSPlatformLock( const mDNS
* const inMDNS
)
453 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
456 if( semTake( inMDNS
->p
->lock
, 60 * sysClkRateGet() ) != OK
)
458 dmsg( kDebugLevelTragic
, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS
->p
->lock
, taskIdSelf() );
459 debug_stack_trace(); // 1) Print Stack Trace.
460 semShow( inMDNS
->p
->lock
, 1 ); // 2) Print semaphore info, including which tasks are pending on it.
461 taskSuspend( 0 ); // 3) Suspend task. Can be resumed from the console for debugging.
464 semTake( inMDNS
->p
->lock
, WAIT_FOREVER
);
468 //===========================================================================================================================
469 // mDNSPlatformUnlock
470 //===========================================================================================================================
472 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
474 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
476 // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time.
477 // We only need to wake up if we're not already inside the task. This avoids filling up the command queue.
479 if( taskIdSelf() != inMDNS
->p
->taskID
)
481 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
483 semGive( inMDNS
->p
->lock
);
486 //===========================================================================================================================
487 // mDNSPlatformStrLen
488 //===========================================================================================================================
490 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
494 return( (mDNSu32
) strlen( (const char *) inSrc
) );
497 //===========================================================================================================================
498 // mDNSPlatformStrCopy
499 //===========================================================================================================================
501 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
506 strcpy( (char *) inDst
, (const char*) inSrc
);
509 //===========================================================================================================================
510 // mDNSPlatformMemCopy
511 //===========================================================================================================================
513 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
518 memcpy( inDst
, inSrc
, inSize
);
521 //===========================================================================================================================
522 // mDNSPlatformMemSame
523 //===========================================================================================================================
525 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
530 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
533 //===========================================================================================================================
534 // mDNSPlatformMemZero
535 //===========================================================================================================================
537 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
541 memset( inDst
, 0, inSize
);
544 //===========================================================================================================================
545 // mDNSPlatformMemAllocate
546 //===========================================================================================================================
548 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
554 mem
= malloc( inSize
);
560 //===========================================================================================================================
561 // mDNSPlatformMemFree
562 //===========================================================================================================================
564 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
567 if( inMem
) free( inMem
);
570 //===========================================================================================================================
571 // mDNSPlatformRandomSeed
572 //===========================================================================================================================
574 mDNSexport mDNSu32
mDNSPlatformRandomSeed( void )
579 //===========================================================================================================================
580 // mDNSPlatformTimeInit
581 //===========================================================================================================================
583 mDNSexport mStatus
mDNSPlatformTimeInit( void )
585 // No special setup is required on VxWorks -- we just use tickGet().
587 return( mStatus_NoError
);
590 //===========================================================================================================================
591 // mDNSPlatformRawTime
592 //===========================================================================================================================
594 mDNSs32
mDNSPlatformRawTime( void )
596 return( (mDNSs32
) tickGet() );
599 //===========================================================================================================================
601 //===========================================================================================================================
603 mDNSexport mDNSs32
mDNSPlatformUTC( void )
605 return( (mDNSs32
) time( NULL
) );
608 //===========================================================================================================================
609 // mDNSPlatformInterfaceIDfromInterfaceIndex
610 //===========================================================================================================================
612 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS
*const inMDNS
, mDNSu32 inIndex
)
614 NetworkInterfaceInfoVxWorks
* i
;
616 if( inIndex
== (mDNSu32
) -1 ) return( mDNSInterface_LocalOnly
);
619 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
621 // Don't get tricked by inactive interfaces with no InterfaceID set.
623 if( i
->ifinfo
.InterfaceID
&& ( i
->scopeID
== inIndex
) ) return( i
->ifinfo
.InterfaceID
);
629 //===========================================================================================================================
630 // mDNSPlatformInterfaceIndexfromInterfaceID
631 //===========================================================================================================================
633 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS
*const inMDNS
, mDNSInterfaceID inID
)
635 NetworkInterfaceInfoVxWorks
* i
;
637 if( inID
== mDNSInterface_LocalOnly
) return( (mDNSu32
) -1 );
640 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
642 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
643 if( i
) return( i
->scopeID
);
648 //===========================================================================================================================
649 // mDNSPlatformInterfaceNameToID
650 //===========================================================================================================================
652 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
654 NetworkInterfaceInfoVxWorks
* i
;
656 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
658 // Don't get tricked by inactive interfaces with no InterfaceID set.
660 if( i
->ifinfo
.InterfaceID
&& ( strcmp( i
->ifinfo
.ifname
, inName
) == 0 ) )
662 *outID
= (mDNSInterfaceID
) i
;
663 return( mStatus_NoError
);
666 return( mStatus_NoSuchNameErr
);
669 //===========================================================================================================================
670 // mDNSPlatformInterfaceIDToInfo
671 //===========================================================================================================================
673 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
675 NetworkInterfaceInfoVxWorks
* i
;
677 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
679 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
680 if( !i
) return( mStatus_NoSuchNameErr
);
682 outInfo
->name
= i
->ifinfo
.ifname
;
683 outInfo
->ip
= i
->ifinfo
.ip
;
684 return( mStatus_NoError
);
687 //===========================================================================================================================
689 //===========================================================================================================================
691 #if( MDNS_DEBUGMSGS > 0 )
692 mDNSexport
void debugf_( const char *inFormat
, ... )
697 va_start( args
, inFormat
);
698 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
701 dlog( kDebugLevelInfo
, "%s\n", buffer
);
705 //===========================================================================================================================
707 //===========================================================================================================================
709 #if( MDNS_DEBUGMSGS > 1 )
710 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
715 va_start( args
, inFormat
);
716 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
719 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
723 //===========================================================================================================================
725 //===========================================================================================================================
727 mDNSexport
void LogMsg( const char *inFormat
, ... )
733 va_start( args
, inFormat
);
734 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
737 dlog( kDebugLevelWarning
, "%s\n", buffer
);
739 DEBUG_UNUSED( inFormat
);
744 //===========================================================================================================================
746 //===========================================================================================================================
748 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... )
753 va_start( args
, inFormat
);
754 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
757 if( inLevel
>= gMDNSDebugOverrideLevel
) inLevel
= kDebugLevelMax
;
758 dlog( inLevel
, "%s", buffer
);
764 #pragma mark == Interfaces ==
767 //===========================================================================================================================
768 // UpdateInterfaceList
769 //===========================================================================================================================
771 #if( MDNS_ENABLE_PPP )
773 // Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
775 #define IsCompatibleInterface( IFA ) \
776 ( ( ( IFA )->ifa_flags & IFF_UP ) && \
777 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
778 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \
779 ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
781 #define IsCompatibleInterface( IFA ) \
782 ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \
783 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
784 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) )
787 #define IsLinkLocalSockAddr( SA ) \
788 ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
789 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
790 ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
791 : IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
793 #define FamilyToString( X ) \
794 ( ( ( X ) == AF_INET ) ? "AF_INET" : \
795 ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
796 ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
799 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
)
802 struct ifaddrs
* ifaList
;
803 struct ifaddrs
* ifa
;
807 struct ifaddrs
* loopbackV4
;
808 struct ifaddrs
* loopbackV6
;
809 mDNSEthAddr primaryMAC
;
811 char defaultName
[ 64 ];
812 NetworkInterfaceInfoVxWorks
* i
;
813 domainlabel nicelabel
;
814 domainlabel hostlabel
;
822 primaryMAC
= zeroEthAddr
;
824 // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
826 infoSock
= socket( AF_INET6
, SOCK_DGRAM
, 0 );
827 check_translated_errno( IsValidSocket( infoSock
), errno_compat(), kUnknownErr
);
829 // Run through the entire list of interfaces.
831 err
= getifaddrs( &ifaList
);
832 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
834 for( ifa
= ifaList
; ifa
; ifa
= ifa
->ifa_next
)
838 family
= ifa
->ifa_addr
->sa_family
;
839 dmsg( kDebugLevelVerbose
, DEBUG_NAME
"%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__
,
840 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), ifa
->ifa_flags
, FamilyToString( family
), family
);
842 // Save off the MAC address of the first Ethernet-ish interface.
844 if( family
== AF_LINK
)
846 struct sockaddr_dl
* sdl
;
848 sdl
= (struct sockaddr_dl
*) ifa
->ifa_addr
;
849 if( ( sdl
->sdl_type
== IFT_ETHER
) && ( sdl
->sdl_alen
== sizeof( primaryMAC
) &&
850 mDNSSameEthAddress( &primaryMAC
, &zeroEthAddr
) ) )
852 memcpy( primaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6 );
856 if( !IsCompatibleInterface( ifa
) ) continue;
858 // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
860 if( IsLinkLocalSockAddr( ifa
->ifa_addr
) )
862 struct ifaddrs
* ifaLL
;
864 for( ifaLL
= ifaList
; ifaLL
; ifaLL
= ifaLL
->ifa_next
)
866 if( ifaLL
->ifa_addr
->sa_family
!= family
) continue;
867 if( !IsCompatibleInterface( ifaLL
) ) continue;
868 if( strcmp( ifaLL
->ifa_name
, ifa
->ifa_name
) != 0 ) continue;
869 if( !IsLinkLocalSockAddr( ifaLL
->ifa_addr
) ) break;
873 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %8s(%d) skipping link-local alias\n", __ROUTINE__
,
874 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
) );
879 // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use.
880 // If this is a loopback interface, save it off since we may add it later if there are no other interfaces.
881 // Otherwise, add the interface to the list.
884 if( ( family
== AF_INET6
) && IsValidSocket( infoSock
) )
886 struct sockaddr_in6
* sa6
;
887 struct in6_ifreq ifr6
;
889 sa6
= (struct sockaddr_in6
*) ifa
->ifa_addr
;
890 memset( &ifr6
, 0, sizeof( ifr6
) );
891 strcpy( ifr6
.ifr_name
, ifa
->ifa_name
);
892 ifr6
.ifr_addr
= *sa6
;
893 if( ioctl( infoSock
, SIOCGIFAFLAG_IN6
, (int) &ifr6
) != -1 )
895 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
899 // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is
900 // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an
901 // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround,
902 // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks.
904 if( flags
& ( IN6_IFF_DUPLICATED
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
) )
906 dmsg( kDebugLevelNotice
, DEBUG_NAME
"%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__
,
907 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), flags
);
910 if( ifa
->ifa_flags
& IFF_LOOPBACK
)
912 if( family
== AF_INET
) loopbackV4
= ifa
;
913 else loopbackV6
= ifa
;
917 if( ( family
== AF_INET
) && gMDNSDeferIPv4
&& IsLinkLocalSockAddr( ifa
->ifa_addr
) ) continue;
918 i
= AddInterfaceToList( inMDNS
, ifa
, inUTC
);
919 if( i
&& i
->multicast
)
921 if( family
== AF_INET
) foundV4
= mDNStrue
;
922 else foundV6
= mDNStrue
;
927 // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
929 if( !foundV4
&& loopbackV4
) AddInterfaceToList( inMDNS
, loopbackV4
, inUTC
);
930 if( !foundV6
&& loopbackV6
) AddInterfaceToList( inMDNS
, loopbackV6
, inUTC
);
931 freeifaddrs( ifaList
);
932 if( IsValidSocket( infoSock
) ) close_compat( infoSock
);
934 // The list is complete. Set the McastTxRx setting for each interface. We always send and receive using IPv4.
935 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
936 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large, configured network,
937 // which means there's a good chance that most or all the other devices on that network should also have v4.
938 // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
939 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
940 // so we are willing to make that sacrifice.
942 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
948 txrx
= i
->multicast
&& ( ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4( inMDNS
, i
->scopeID
) );
949 if( i
->ifinfo
.McastTxRx
!= txrx
)
951 i
->ifinfo
.McastTxRx
= txrx
;
952 i
->exists
= 2; // 2=state change; need to de-register and re-register this interface.
957 // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
959 mDNS_snprintf( defaultName
, sizeof( defaultName
), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
960 primaryMAC
.b
[ 0 ], primaryMAC
.b
[ 1 ], primaryMAC
.b
[ 2 ], primaryMAC
.b
[ 3 ], primaryMAC
.b
[ 4 ], primaryMAC
.b
[ 5 ] );
962 MakeDomainLabelFromLiteralString( &nicelabel
, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
963 if( nicelabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel
, defaultName
);
965 // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
967 MakeDomainLabelFromLiteralString( &tmp
, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device.
968 ConvertUTF8PstringToRFC1034HostLabel( tmp
.c
, &hostlabel
);
969 if( hostlabel
.c
[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel
.c
, &hostlabel
);
970 if( hostlabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel
, defaultName
);
972 // Update our globals and mDNS with the new labels.
974 if( !SameDomainLabel( inMDNS
->p
->userNiceLabel
.c
, nicelabel
.c
) )
976 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating nicelabel to \"%#s\"\n", nicelabel
.c
);
977 inMDNS
->p
->userNiceLabel
= nicelabel
;
978 inMDNS
->nicelabel
= nicelabel
;
980 if( !SameDomainLabel( inMDNS
->p
->userHostLabel
.c
, hostlabel
.c
) )
982 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating hostlabel to \"%#s\"\n", hostlabel
.c
);
983 inMDNS
->p
->userHostLabel
= hostlabel
;
984 inMDNS
->hostlabel
= hostlabel
;
985 mDNS_SetFQDN( inMDNS
);
987 return( mStatus_NoError
);
990 //===========================================================================================================================
991 // AddInterfaceToList
992 //===========================================================================================================================
994 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
)
1000 NetworkInterfaceInfoVxWorks
** p
;
1001 NetworkInterfaceInfoVxWorks
* i
;
1005 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ip
);
1006 require_noerr( err
, exit
);
1008 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &mask
);
1009 require_noerr( err
, exit
);
1011 // Search for an existing interface with the same info. If found, just return that one.
1013 scopeID
= if_nametoindex( inIFA
->ifa_name
);
1015 for( p
= &inMDNS
->p
->interfaceList
; *p
; p
= &( *p
)->next
)
1017 if( ( scopeID
== ( *p
)->scopeID
) && mDNSSameAddress( &ip
, &( *p
)->ifinfo
.ip
) )
1019 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__
,
1021 ( *p
)->exists
= mDNStrue
;
1027 // Allocate the new interface info and fill it out.
1029 i
= (NetworkInterfaceInfoVxWorks
*) calloc( 1, sizeof( *i
) );
1032 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__
, scopeID
, &ip
, i
);
1033 strncpy( i
->ifinfo
.ifname
, inIFA
->ifa_name
, sizeof( i
->ifinfo
.ifname
) );
1034 i
->ifinfo
.ifname
[ sizeof( i
->ifinfo
.ifname
) - 1 ] = '\0';
1035 i
->ifinfo
.InterfaceID
= NULL
;
1037 i
->ifinfo
.mask
= mask
;
1038 i
->ifinfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1039 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList.
1042 i
->exists
= mDNStrue
;
1043 i
->lastSeen
= inUTC
;
1044 i
->scopeID
= scopeID
;
1045 i
->family
= inIFA
->ifa_addr
->sa_family
;
1046 i
->multicast
= ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTOPOINT
);
1049 i
->ss
.sockV4
= kInvalidSocketRef
;
1050 i
->ss
.sockV6
= kInvalidSocketRef
;
1057 //===========================================================================================================================
1058 // SetupActiveInterfaces
1060 // Returns a count of non-link local IPv4 addresses registered.
1061 //===========================================================================================================================
1063 #define mDNSAddressIsNonLinkLocalIPv4( X ) \
1064 ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
1066 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1069 NetworkInterfaceInfoVxWorks
* i
;
1072 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1074 NetworkInterfaceInfo
* n
;
1075 NetworkInterfaceInfoVxWorks
* primary
;
1077 if( !i
->exists
) continue;
1079 // Search for the primary interface and sanity check it.
1082 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1085 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! didn't find %s(%u)\n", __ROUTINE__
, i
->ifinfo
.ifname
, i
->scopeID
);
1088 if( n
->InterfaceID
&& ( n
->InterfaceID
!= (mDNSInterfaceID
) primary
) )
1090 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__
,
1091 n
->InterfaceID
, primary
);
1092 n
->InterfaceID
= NULL
;
1095 // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface.
1096 // so we don't need to call it again. Otherwise, register the interface with mDNS.
1098 if( !n
->InterfaceID
)
1102 n
->InterfaceID
= (mDNSInterfaceID
) primary
;
1104 // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away.
1105 // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds.
1106 // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
1108 flapping
= ( ( inUTC
- i
->lastSeen
) > 0 ) && ( ( inUTC
- i
->lastSeen
) < 60 );
1109 mDNS_RegisterInterface( inMDNS
, n
, flapping
? mDNSPlatformOneSecond
* 5 : 0 );
1110 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1112 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__
,
1113 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
,
1114 flapping
? " (Flapping)" : "",
1115 n
->InterfaceActive
? " (Primary)" : "" );
1118 // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we
1119 // don't need a socket since unicast traffic will be handled on the unicast socket.
1125 if( ( ( i
->family
== AF_INET
) && !IsValidSocket( primary
->ss
.sockV4
) ) ||
1126 ( ( i
->family
== AF_INET6
) && !IsValidSocket( primary
->ss
.sockV6
) ) )
1128 err
= SetupSocket( inMDNS
, &i
->ifinfo
.ip
, mDNStrue
, i
->family
, &primary
->ss
);
1134 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__
,
1135 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
);
1141 //===========================================================================================================================
1142 // MarkAllInterfacesInactive
1143 //===========================================================================================================================
1145 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1147 NetworkInterfaceInfoVxWorks
* i
;
1149 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1151 if( !i
->exists
) continue;
1152 i
->lastSeen
= inUTC
;
1153 i
->exists
= mDNSfalse
;
1157 //===========================================================================================================================
1158 // ClearInactiveInterfaces
1160 // Returns count of non-link local IPv4 addresses de-registered.
1161 //===========================================================================================================================
1163 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
)
1166 NetworkInterfaceInfoVxWorks
* i
;
1167 NetworkInterfaceInfoVxWorks
** p
;
1170 // If an interface is going away, then de-register it from mDNSCore.
1171 // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away.
1172 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1173 // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though:
1174 // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that
1175 // interface. (Not yet implemented, but a good idea anyway.).
1178 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1180 NetworkInterfaceInfoVxWorks
* primary
;
1182 // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
1184 if( !i
->ifinfo
.InterfaceID
) continue;
1185 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1186 if( ( i
->exists
== 0 ) || ( i
->exists
== 2 ) || ( i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
) primary
) )
1188 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__
,
1189 i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1190 i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1192 mDNS_DeregisterInterface( inMDNS
, &i
->ifinfo
);
1193 i
->ifinfo
.InterfaceID
= NULL
;
1194 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1199 // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
1201 p
= &inMDNS
->p
->interfaceList
;
1206 // 2. Close all our sockets. We'll recreate them later as needed.
1207 // (We may have previously had both v4 and v6, and we may not need both any more.).
1209 ForgetSocket( &i
->ss
.sockV4
);
1210 ForgetSocket( &i
->ss
.sockV6
);
1212 // 3. If no longer active, remove the interface from the list and free its memory.
1220 check_string( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0, "closing with in-use records!" );
1221 deleteIt
= mDNStrue
;
1225 if( i
->lastSeen
== inUTC
) i
->lastSeen
= inUTC
- 1;
1226 deleteIt
= ( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0 ) && ( ( inUTC
- i
->lastSeen
) >= 60 );
1228 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__
,
1229 deleteIt
? "Deleting" : "Holding", i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1230 inUTC
- i
->lastSeen
, i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1243 //===========================================================================================================================
1245 //===========================================================================================================================
1247 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
)
1249 #if( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1250 NetworkInterfaceInfoVxWorks
* i
;
1252 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1254 if( i
->exists
&& ( i
->scopeID
== inScopeID
) && mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) )
1261 DEBUG_UNUSED( inMDNS
);
1262 DEBUG_UNUSED( inScopeID
);
1268 //===========================================================================================================================
1269 // FindInterfaceByIndex
1270 //===========================================================================================================================
1272 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
)
1274 NetworkInterfaceInfoVxWorks
* i
;
1276 check( inIndex
!= 0 );
1278 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1280 if( i
->exists
&& ( i
->scopeID
== inIndex
) &&
1281 ( MDNS_AAAA_OVER_IPV4
||
1282 ( ( inFamily
== AF_INET
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ) ||
1283 ( ( inFamily
== AF_INET6
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) ) ) )
1291 //===========================================================================================================================
1293 //===========================================================================================================================
1295 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
)
1298 SocketRef
* sockPtr
;
1306 sockPtr
= ( inFamily
== AF_INET
) ? &inSS
->sockV4
: &inSS
->sockV6
;
1307 port
= ( inMcast
|| inMDNS
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1309 sock
= socket( inFamily
, SOCK_DGRAM
, IPPROTO_UDP
);
1310 err
= translate_errno( IsValidSocket( sock
), errno_compat(), mStatus_UnknownErr
);
1311 require_noerr( err
, exit
);
1313 // Allow multiple listeners if this is a multicast port.
1315 if( port
.NotAnInteger
)
1317 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEPORT
, (char *) &on
, sizeof( on
) );
1318 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1321 // Set up the socket based on the family (IPv4 or IPv6).
1323 if( inFamily
== AF_INET
)
1325 const int ttlV4
= 255;
1326 const u_char ttlV4Mcast
= 255;
1327 struct sockaddr_in sa4
;
1329 // Receive destination addresses so we know which address the packet was sent to.
1331 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVDSTADDR
, (char *) &on
, sizeof( on
) );
1332 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1334 // Receive interface indexes so we know which interface received the packet.
1336 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVIF
, (char *) &on
, sizeof( on
) );
1337 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1339 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1343 struct in_addr addrV4
;
1344 struct ip_mreq mreqV4
;
1346 addrV4
.s_addr
= inAddr
->ip
.v4
.NotAnInteger
;
1347 mreqV4
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1348 mreqV4
.imr_interface
= addrV4
;
1349 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqV4
, sizeof( mreqV4
) );
1350 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1352 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addrV4
, sizeof( addrV4
) );
1353 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1356 // Send unicast packets with TTL 255 (helps against spoofing).
1358 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &ttlV4
, sizeof( ttlV4
) );
1359 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1361 // Send multicast packets with TTL 255 (helps against spoofing).
1363 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &ttlV4Mcast
, sizeof( ttlV4Mcast
) );
1364 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1366 // Start listening for packets.
1368 memset( &sa4
, 0, sizeof( sa4
) );
1369 sa4
.sin_len
= sizeof( sa4
);
1370 sa4
.sin_family
= AF_INET
;
1371 sa4
.sin_port
= port
.NotAnInteger
;
1372 sa4
.sin_addr
.s_addr
= htonl( INADDR_ANY
); // We want to receive multicasts AND unicasts on this socket.
1373 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
1374 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1376 else if( inFamily
== AF_INET6
)
1378 struct sockaddr_in6 sa6
;
1379 const int ttlV6
= 255;
1381 // Receive destination addresses and interface index so we know where the packet was received and intended.
1383 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &on
, sizeof( on
) );
1384 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1386 // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
1388 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &on
, sizeof( on
) );
1389 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1391 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1396 struct ipv6_mreq mreqV6
;
1398 ifindex
= inSS
->info
->scopeID
;
1399 mreqV6
.ipv6mr_interface
= ifindex
;
1400 mreqV6
.ipv6mr_multiaddr
= *( (struct in6_addr
* ) &AllDNSLinkGroupv6
);
1401 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqV6
, sizeof( mreqV6
) );
1402 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1404 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &ifindex
, sizeof( ifindex
) );
1405 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1408 // Send unicast packets with TTL 255 (helps against spoofing).
1410 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1411 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1413 // Send multicast packets with TTL 255 (helps against spoofing).
1415 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1416 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1418 // Receive our own packets for same-machine operation.
1420 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &on
, sizeof( on
) );
1421 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1423 // Start listening for packets.
1425 memset( &sa6
, 0, sizeof( sa6
) );
1426 sa6
.sin6_len
= sizeof( sa6
);
1427 sa6
.sin6_family
= AF_INET6
;
1428 sa6
.sin6_port
= port
.NotAnInteger
;
1429 sa6
.sin6_flowinfo
= 0;
1430 sa6
.sin6_addr
= in6addr_any
; // We want to receive multicasts AND unicasts on this socket.
1431 sa6
.sin6_scope_id
= 0;
1432 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
1433 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1437 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inFamily
);
1438 err
= kUnsupportedErr
;
1442 // Make the socket non-blocking so we can potentially get multiple packets per select call.
1444 err
= ioctl( sock
, FIONBIO
, (int) &on
);
1445 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1448 sock
= kInvalidSocketRef
;
1449 err
= mStatus_NoError
;
1452 if( IsValidSocket( sock
) ) close_compat( sock
);
1456 //===========================================================================================================================
1457 // SockAddrToMDNSAddr
1458 //===========================================================================================================================
1460 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
)
1467 if( inSA
->sa_family
== AF_INET
)
1469 struct sockaddr_in
* sa4
;
1471 sa4
= (struct sockaddr_in
*) inSA
;
1472 outIP
->type
= mDNSAddrType_IPv4
;
1473 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1474 err
= mStatus_NoError
;
1476 else if( inSA
->sa_family
== AF_INET6
)
1478 struct sockaddr_in6
* sa6
;
1480 sa6
= (struct sockaddr_in6
*) inSA
;
1481 outIP
->type
= mDNSAddrType_IPv6
;
1482 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1483 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) ) outIP
->ip
.v6
.w
[ 1 ] = 0;
1484 err
= mStatus_NoError
;
1488 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family (%d)\n", __ROUTINE__
, inSA
->sa_family
);
1489 err
= mStatus_BadParamErr
;
1496 #pragma mark == Commands ==
1499 //===========================================================================================================================
1501 //===========================================================================================================================
1503 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1507 err
= pipeDevCreate( "/pipe/mDNS", 32, 1 );
1508 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1510 inMDNS
->p
->commandPipe
= open( "/pipe/mDNS", O_RDWR
, 0 );
1511 err
= translate_errno( inMDNS
->p
->commandPipe
!= ERROR
, errno_compat(), mStatus_UnsupportedErr
);
1512 require_noerr( err
, exit
);
1518 //===========================================================================================================================
1519 // TearDownCommandPipe
1520 //===========================================================================================================================
1522 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1526 if( inMDNS
->p
->commandPipe
!= ERROR
)
1528 err
= close( inMDNS
->p
->commandPipe
);
1529 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1530 inMDNS
->p
->commandPipe
= ERROR
;
1532 err
= pipeDevDelete( "/pipe/mDNS", FALSE
);
1533 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1535 return( mStatus_NoError
);
1538 //===========================================================================================================================
1540 //===========================================================================================================================
1542 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1546 require_action_quiet( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1548 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1549 err
= translate_errno( err
>= 0, errno_compat(), kWriteErr
);
1550 require_noerr( err
, exit
);
1556 //===========================================================================================================================
1558 //===========================================================================================================================
1560 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1563 MDNSPipeCommandCode cmd
;
1566 err
= read( inMDNS
->p
->commandPipe
, &cmd
, sizeof( cmd
) );
1567 err
= translate_errno( err
>= 0, errno_compat(), kReadErr
);
1568 require_noerr( err
, exit
);
1572 case kMDNSPipeCommandCodeReschedule
: // Reschedule: just break out to re-run mDNS_Execute.
1575 case kMDNSPipeCommandCodeReconfigure
: // Reconfigure: rebuild the interface list after a config change.
1576 dmsg( kDebugLevelInfo
, DEBUG_NAME
"*** NETWORK CONFIGURATION CHANGE ***\n" );
1577 mDNSPlatformLock( inMDNS
);
1579 utc
= mDNSPlatformUTC();
1580 MarkAllInterfacesInactive( inMDNS
, utc
);
1581 UpdateInterfaceList( inMDNS
, utc
);
1582 ClearInactiveInterfaces( inMDNS
, utc
, mDNSfalse
);
1583 SetupActiveInterfaces( inMDNS
, utc
);
1585 mDNSPlatformUnlock( inMDNS
);
1586 if( inMDNS
->MainCallback
) inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1589 case kMDNSPipeCommandCodeQuit
: // Quit: just set a flag so the task exits cleanly.
1590 inMDNS
->p
->quit
= mDNStrue
;
1594 dmsg( kDebugLevelError
, DEBUG_NAME
"unknown pipe command (%d)\n", cmd
);
1595 err
= mStatus_BadParamErr
;
1605 #pragma mark == Threads ==
1608 //===========================================================================================================================
1610 //===========================================================================================================================
1612 mDNSlocal
void Task( mDNS
*inMDNS
)
1618 struct timeval timeout
;
1619 NetworkInterfaceInfoVxWorks
* i
;
1625 err
= TaskInit( inMDNS
);
1626 require_noerr( err
, exit
);
1628 while( !inMDNS
->p
->quit
)
1630 // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
1632 nextEvent
= mDNS_Execute( inMDNS
);
1633 TaskSetupSelect( inMDNS
, &readSet
, &maxFd
, nextEvent
, &timeout
);
1634 n
= select( maxFd
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1635 check_translated_errno( n
>= 0, errno_compat(), kUnknownErr
);
1636 if( n
== 0 ) continue;
1638 // Process interface-specific sockets with pending data.
1641 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1644 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1646 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1650 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1652 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1657 // Process unicast sockets with pending data.
1659 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1660 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1662 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1665 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1666 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1668 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1672 // Processing pending commands.
1674 fd
= inMDNS
->p
->commandPipe
;
1676 if( FD_ISSET( fd
, &readSet
) )
1678 ProcessCommand( inMDNS
);
1681 check_string( n
> 0, "select said something was readable, but nothing was" );
1688 //===========================================================================================================================
1690 //===========================================================================================================================
1692 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1698 inMDNS
->p
->taskID
= taskIdSelf();
1700 err
= SetupCommandPipe( inMDNS
);
1701 require_noerr( err
, exit
);
1703 inMDNS
->CanReceiveUnicastOn5353
= mDNStrue
;
1705 // Set up the HINFO string using the description property (e.g. "Device V1.0").
1707 inMDNS
->HIHardware
.c
[ 0 ] = 11;
1708 memcpy( &inMDNS
->HIHardware
.c
[ 1 ], "Device V1.0", inMDNS
->HIHardware
.c
[ 0 ] ); // $$$ Implementers: Fill in real info.
1710 // Set up the unicast sockets.
1712 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET
, &inMDNS
->p
->unicastSS
);
1714 if( err
== mStatus_NoError
)
1716 struct sockaddr_in sa4
;
1718 len
= sizeof( sa4
);
1719 err
= getsockname( inMDNS
->p
->unicastSS
.sockV4
, (struct sockaddr
*) &sa4
, &len
);
1720 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1721 if( err
== 0 ) inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
1724 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET6
, &inMDNS
->p
->unicastSS
);
1726 if( err
== mStatus_NoError
)
1728 struct sockaddr_in6 sa6
;
1730 len
= sizeof( sa6
);
1731 err
= getsockname( inMDNS
->p
->unicastSS
.sockV6
, (struct sockaddr
*) &sa6
, &len
);
1732 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1733 if( err
== 0 ) inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
1736 // Set up the interfaces.
1738 utc
= mDNSPlatformUTC();
1739 UpdateInterfaceList( inMDNS
, utc
);
1740 SetupActiveInterfaces( inMDNS
, utc
);
1741 err
= mStatus_NoError
;
1744 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1746 inMDNS
->p
->initErr
= err
;
1747 semGive( inMDNS
->p
->initEvent
);
1751 //===========================================================================================================================
1753 //===========================================================================================================================
1755 mDNSlocal
void TaskTerm( mDNS
*inMDNS
)
1760 // Tear down all interfaces.
1762 utc
= mDNSPlatformUTC();
1763 MarkAllInterfacesInactive( inMDNS
, utc
);
1764 ClearInactiveInterfaces( inMDNS
, utc
, mDNStrue
);
1765 check_string( !inMDNS
->p
->interfaceList
, "LEAK: closing without deleting all interfaces" );
1767 // Close unicast sockets.
1769 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV4
);
1770 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV6
);
1772 // Tear down everything else that was set up in TaskInit then signal back that we're done.
1774 err
= TearDownCommandPipe( inMDNS
);
1777 err
= semGive( inMDNS
->p
->quitEvent
);
1778 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1781 //===========================================================================================================================
1783 //===========================================================================================================================
1785 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
)
1787 NetworkInterfaceInfoVxWorks
* i
;
1795 // Add the interface-specific sockets.
1797 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1800 if( IsValidSocket( fd
) )
1802 FD_SET( fd
, outSet
);
1803 if( fd
> maxFd
) maxFd
= fd
;
1807 if( IsValidSocket( fd
) )
1809 FD_SET( fd
, outSet
);
1810 if( fd
> maxFd
) maxFd
= fd
;
1814 // Add the unicast sockets.
1816 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1817 if( IsValidSocket( fd
) )
1819 FD_SET( fd
, outSet
);
1820 if( fd
> maxFd
) maxFd
= fd
;
1823 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1824 if( IsValidSocket( fd
) )
1826 FD_SET( fd
, outSet
);
1827 if( fd
> maxFd
) maxFd
= fd
;
1830 // Add the command pipe.
1832 fd
= inMDNS
->p
->commandPipe
;
1834 FD_SET( fd
, outSet
);
1835 if( fd
> maxFd
) maxFd
= fd
;
1840 // Calculate how long to wait before performing idle processing.
1842 delta
= inNextEvent
- mDNS_TimeNow( inMDNS
);
1845 // The next task time is now or in the past. Set the timeout to fire immediately.
1847 outTimeout
->tv_sec
= 0;
1848 outTimeout
->tv_usec
= 0;
1852 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1853 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1855 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1856 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicro
;
1857 if( outTimeout
->tv_usec
>= 1000000L )
1859 outTimeout
->tv_sec
+= 1;
1860 outTimeout
->tv_usec
= 0;
1865 //===========================================================================================================================
1866 // TaskProcessPackets
1867 //===========================================================================================================================
1869 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
)
1875 struct sockaddr_storage from
;
1878 mDNSAddr senderAddr
;
1879 mDNSIPPort senderPort
;
1882 buf
= (mDNSu8
*) &inMDNS
->imsg
;
1883 size
= sizeof( inMDNS
->imsg
);
1887 n
= mDNSRecvMsg( inSock
, buf
, size
, &from
, sizeof( from
), &fromSize
, &destAddr
, &ifindex
);
1889 if( from
.ss_family
== AF_INET
)
1891 struct sockaddr_in
* sa4
;
1893 sa4
= (struct sockaddr_in
*) &from
;
1894 senderAddr
.type
= mDNSAddrType_IPv4
;
1895 senderAddr
.ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1896 senderPort
.NotAnInteger
= sa4
->sin_port
;
1898 else if( from
.ss_family
== AF_INET6
)
1900 struct sockaddr_in6
* sa6
;
1902 sa6
= (struct sockaddr_in6
*) &from
;
1903 senderAddr
.type
= mDNSAddrType_IPv6
;
1904 senderAddr
.ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1905 senderPort
.NotAnInteger
= sa6
->sin6_port
;
1909 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: WARNING! from addr unknown family %d\n", __ROUTINE__
, from
.ss_family
);
1913 // Even though we indicated a specific interface when joining the multicast group, a weirdness of the
1914 // sockets API means that even though this socket has only officially joined the multicast group
1915 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1916 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1917 // To work around this weirdness, we use the IP_RECVIF/IPV6_PKTINFO options to find the interface
1918 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1920 if( mDNSAddrIsDNSMulticast( &destAddr
) )
1922 if( !inSS
->info
|| !inSS
->info
->exists
)
1924 dpkt( kDebugLevelChatty
- 3, DEBUG_NAME
" ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
1925 &senderAddr
, &destAddr
, inSock
);
1928 if( ifindex
!= inSS
->info
->scopeID
)
1930 #if( DEBUG && MDNS_DEBUG_PACKETS )
1931 char ifname
[ IF_NAMESIZE
];
1934 dpkt( kDebugLevelChatty
- 3,
1935 DEBUG_NAME
" ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n",
1936 &senderAddr
, &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
,
1937 if_indextoname( ifindex
, ifname
), ifindex
);
1941 id
= inSS
->info
->ifinfo
.InterfaceID
;
1942 dpkt( kDebugLevelChatty
- 2, DEBUG_NAME
"recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n",
1943 n
, &senderAddr
, mDNSVal16( senderPort
), &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
, id
);
1947 NetworkInterfaceInfoVxWorks
* i
;
1949 // For unicast packets, try to find the matching interface.
1951 for( i
= inMDNS
->p
->interfaceList
; i
&& ( i
->scopeID
!= ifindex
); i
= i
->next
) {}
1952 if( i
) id
= i
->ifinfo
.InterfaceID
;
1955 mDNSCoreReceive( inMDNS
, buf
, buf
+ n
, &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, id
);
1959 //===========================================================================================================================
1961 //===========================================================================================================================
1967 size_t inBufferSize
,
1970 size_t * outFromSize
,
1971 mDNSAddr
* outDstAddr
,
1972 uint32_t * outIndex
)
1977 char ancillary
[ 1024 ];
1978 struct cmsghdr
* cmPtr
;
1981 // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
1983 iov
.iov_base
= (char *) inBuffer
;
1984 iov
.iov_len
= inBufferSize
;
1985 msg
.msg_name
= (caddr_t
) outFrom
;
1986 msg
.msg_namelen
= inFromSize
;
1989 msg
.msg_control
= (caddr_t
) &ancillary
;
1990 msg
.msg_controllen
= sizeof( ancillary
);
1992 n
= recvmsg( inSock
, &msg
, 0 );
1995 err
= errno_compat();
1996 if( err
!= EWOULDBLOCK
) dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) returned %d, errno %d\n",
1997 __ROUTINE__
, inSock
, n
, err
);
2000 if( msg
.msg_controllen
< sizeof( struct cmsghdr
) )
2002 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
2003 __ROUTINE__
, inSock
, msg
.msg_controllen
, sizeof( struct cmsghdr
) );
2004 n
= mStatus_UnknownErr
;
2007 if( msg
.msg_flags
& MSG_CTRUNC
)
2009 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__
, inSock
, n
);
2010 n
= mStatus_BadFlagsErr
;
2013 *outFromSize
= msg
.msg_namelen
;
2015 // Parse each option out of the ancillary data.
2017 for( cmPtr
= CMSG_FIRSTHDR( &msg
); cmPtr
; cmPtr
= CMSG_NXTHDR( &msg
, cmPtr
) )
2019 if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVDSTADDR
) )
2021 outDstAddr
->type
= mDNSAddrType_IPv4
;
2022 outDstAddr
->ip
.v4
.NotAnInteger
= *( (mDNSu32
*) CMSG_DATA( cmPtr
) );
2024 else if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVIF
) )
2026 struct sockaddr_dl
* sdl
;
2028 sdl
= (struct sockaddr_dl
*) CMSG_DATA( cmPtr
);
2029 *outIndex
= sdl
->sdl_index
;
2031 else if( ( cmPtr
->cmsg_level
== IPPROTO_IPV6
) && ( cmPtr
->cmsg_type
== IPV6_PKTINFO
) )
2033 struct in6_pktinfo
* pi6
;
2035 pi6
= (struct in6_pktinfo
*) CMSG_DATA( cmPtr
);
2036 outDstAddr
->type
= mDNSAddrType_IPv6
;
2037 outDstAddr
->ip
.v6
= *( (mDNSv6Addr
*) &pi6
->ipi6_addr
);
2038 *outIndex
= pi6
->ipi6_ifindex
;
2048 #pragma mark == Debugging ==
2051 #if( DEBUG && MDNS_DEBUG_SHOW )
2052 //===========================================================================================================================
2054 //===========================================================================================================================
2056 void mDNSShow( void );
2058 void mDNSShow( void )
2060 NetworkInterfaceInfoVxWorks
* i
;
2067 dmsg( kDebugLevelMax
, "\n-- mDNS globals --\n" );
2068 dmsg( kDebugLevelMax
, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2069 dmsg( kDebugLevelMax
, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2070 dmsg( kDebugLevelMax
, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2071 dmsg( kDebugLevelMax
, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2072 dmsg( kDebugLevelMax
, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond
);
2073 dmsg( kDebugLevelMax
, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro
);
2074 dmsg( kDebugLevelMax
, " gMDNSPtr = %#p\n", gMDNSPtr
);
2077 dmsg( kDebugLevelMax
, "### mDNS not initialized\n" );
2080 dmsg( kDebugLevelMax
, " nicelabel = \"%#s\"\n", gMDNSPtr
->nicelabel
.c
);
2081 dmsg( kDebugLevelMax
, " hostLabel = \"%#s\"\n", gMDNSPtr
->hostlabel
.c
);
2082 dmsg( kDebugLevelMax
, " MulticastHostname = \"%##s\"\n", gMDNSPtr
->MulticastHostname
.c
);
2083 dmsg( kDebugLevelMax
, " HIHardware = \"%#s\"\n", gMDNSPtr
->HIHardware
.c
);
2084 dmsg( kDebugLevelMax
, " HISoftware = \"%#s\"\n", gMDNSPtr
->HISoftware
.c
);
2085 dmsg( kDebugLevelMax
, " UnicastPort4/6 = %d/%d\n",
2086 mDNSVal16( gMDNSPtr
->UnicastPort4
), mDNSVal16( gMDNSPtr
->UnicastPort6
) );
2087 dmsg( kDebugLevelMax
, " unicastSS.sockV4/V6 = %d/%d\n",
2088 gMDNSPtr
->p
->unicastSS
.sockV4
, gMDNSPtr
->p
->unicastSS
.sockV6
);
2089 dmsg( kDebugLevelMax
, " lock = %#p\n", gMDNSPtr
->p
->lock
);
2090 dmsg( kDebugLevelMax
, " initEvent = %#p\n", gMDNSPtr
->p
->initEvent
);
2091 dmsg( kDebugLevelMax
, " initErr = %ld\n", gMDNSPtr
->p
->initErr
);
2092 dmsg( kDebugLevelMax
, " quitEvent = %#p\n", gMDNSPtr
->p
->quitEvent
);
2093 dmsg( kDebugLevelMax
, " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2094 dmsg( kDebugLevelMax
, " taskID = %#p\n", gMDNSPtr
->p
->taskID
);
2095 dmsg( kDebugLevelMax
, "\n" );
2099 utc
= mDNSPlatformUTC();
2100 dmsg( kDebugLevelMax
, "-- mDNS interfaces --\n" );
2102 for( i
= gMDNSPtr
->p
->interfaceList
; i
; i
= i
->next
)
2104 dmsg( kDebugLevelMax
, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
2105 num
, i
->ifinfo
.ifname
, i
->scopeID
, &i
->ifinfo
.ip
,
2106 i
->ifinfo
.InterfaceID
? " REGISTERED" : "*NOT* registered",
2107 i
->ss
.sockV4
, i
->ss
.sockV6
, utc
- i
->lastSeen
);
2110 dmsg( kDebugLevelMax
, "\n" );
2114 dmsg( kDebugLevelMax
, "-- mDNS resource records --\n" );
2116 for( r
= gMDNSPtr
->ResourceRecords
; r
; r
= r
->next
)
2118 i
= (NetworkInterfaceInfoVxWorks
*) r
->resrec
.InterfaceID
;
2119 if( r
->resrec
.rrtype
== kDNSType_TXT
)
2127 rd
= &r
->resrec
.rdata
->u
;
2128 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num
, i
,
2129 i
? i
->ifinfo
.ifname
: "<any>",
2131 r
->resrec
.rdlength
, r
->resrec
.name
->c
, DNSTypeName( r
->resrec
.rrtype
) );
2135 end
= txt
+ r
->resrec
.rdlength
;
2139 if( ( txt
+ size
) > end
)
2141 dmsg( kDebugLevelMax
, " ### ERROR! txt length byte too big (%u, %u max)\n", size
, end
- txt
);
2144 dmsg( kDebugLevelMax
, " string %2d (%3d bytes): \"%.*s\"\n", nEntries
, size
, size
, txt
);
2151 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %s\n", num
, i
,
2152 i
? i
->ifinfo
.ifname
: "<any>",
2154 ARDisplayString( gMDNSPtr
, r
) );
2158 dmsg( kDebugLevelMax
, "\n");
2160 #endif // DEBUG && MDNS_DEBUG_SHOW