1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #pragma mark == Configuration ==
22 //===========================================================================================================================
24 //===========================================================================================================================
26 #define DEBUG_NAME "[mDNS] "
27 #define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
28 #define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
29 #define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
30 #define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough.
31 #define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines.
32 #define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details).
44 #include <sys/types.h>
46 #include <arpa/inet.h>
48 #include <net/if_dl.h>
49 #include <net/if_types.h>
50 #include <net/ifaddrs.h>
51 #include <netinet6/in6_var.h>
52 #include <netinet/if_ether.h>
53 #include <netinet/in.h>
54 #include <netinet/ip.h>
55 #include <sys/ioctl.h>
56 #include <sys/socket.h>
62 #include "selectLib.h"
69 #include "CommonServices.h"
70 #include "DebugServices.h"
71 #include "DNSCommon.h"
72 #include "mDNSEmbeddedAPI.h"
74 #include "mDNSVxWorks.h"
77 #pragma mark == Constants ==
80 //===========================================================================================================================
82 //===========================================================================================================================
84 typedef uint8_t MDNSPipeCommandCode
;
86 #define kMDNSPipeCommandCodeInvalid 0
87 #define kMDNSPipeCommandCodeReschedule 1
88 #define kMDNSPipeCommandCodeReconfigure 2
89 #define kMDNSPipeCommandCodeQuit 3
92 #pragma mark == Prototypes ==
95 //===========================================================================================================================
97 //===========================================================================================================================
100 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... );
102 #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
104 #define dmsg( LEVEL, ARGS... )
107 #if( DEBUG && MDNS_DEBUG_PACKETS )
108 #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
110 #define dpkt( LEVEL, ARGS... )
113 #define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
114 #define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
118 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
);
119 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
);
120 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
);
121 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
);
122 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
);
123 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
);
124 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
);
125 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
);
126 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
);
130 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
131 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
132 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
133 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
137 mDNSlocal
void Task( mDNS
*inMDNS
);
138 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
139 mDNSlocal
void TaskTerm( mDNS
*inMDNS
);
140 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
);
141 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
);
149 size_t * outFromSize
,
150 mDNSAddr
* outDstAddr
,
151 uint32_t * outIndex
);
153 // DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
159 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
160 struct mDNSPlatformInterfaceInfo
166 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
167 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
174 #pragma mark == Globals ==
177 //===========================================================================================================================
179 //===========================================================================================================================
181 debug_log_new_default_category( mdns
);
183 mDNSexport mDNSs32 mDNSPlatformOneSecond
;
184 mDNSlocal mDNSs32 gMDNSTicksToMicro
= 0;
185 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
186 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
187 mDNSlocal mDNSBool gMDNSDeferIPv4
= mDNSfalse
;
189 DebugLevel gMDNSDebugOverrideLevel
= kDebugLevelMax
;
196 //===========================================================================================================================
198 //===========================================================================================================================
200 void mDNSReconfigure( void )
202 if( gMDNSPtr
) SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
205 //===========================================================================================================================
207 //===========================================================================================================================
209 void mDNSDeferIPv4( mDNSBool inDefer
)
211 gMDNSDeferIPv4
= inDefer
;
218 //===========================================================================================================================
220 //===========================================================================================================================
222 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
227 mDNSPlatformOneSecond
= sysClkRateGet();
228 gMDNSTicksToMicro
= ( 1000000L / mDNSPlatformOneSecond
);
230 // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
232 mDNSPlatformMemZero( &gMDNSPlatformSupport
, sizeof( gMDNSPlatformSupport
) );
233 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
234 inMDNS
->p
->unicastSS
.info
= NULL
;
235 inMDNS
->p
->unicastSS
.sockV4
= kInvalidSocketRef
;
236 inMDNS
->p
->unicastSS
.sockV6
= kInvalidSocketRef
;
237 inMDNS
->p
->initErr
= mStatus_NotInitializedErr
;
238 inMDNS
->p
->commandPipe
= ERROR
;
239 inMDNS
->p
->taskID
= ERROR
;
241 inMDNS
->p
->lock
= semMCreate( SEM_Q_FIFO
);
242 require_action( inMDNS
->p
->lock
, exit
, err
= mStatus_NoMemoryErr
);
244 inMDNS
->p
->initEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
245 require_action( inMDNS
->p
->initEvent
, exit
, err
= mStatus_NoMemoryErr
);
247 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
248 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
250 // Start the task and wait for it to initialize. The task does the full initialization from its own context
251 // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers).
252 // We wait here until the init is complete because it needs to be ready to use as soon as this function returns.
254 id
= taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR
) Task
, (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
255 err
= translate_errno( id
!= ERROR
, errno_compat(), mStatus_NoMemoryErr
);
256 require_noerr( err
, exit
);
258 err
= semTake( inMDNS
->p
->initEvent
, WAIT_FOREVER
);
259 if( err
== OK
) err
= inMDNS
->p
->initErr
;
260 require_noerr( err
, exit
);
263 mDNSCoreInitComplete( inMDNS
, err
);
266 if( err
) mDNSPlatformClose( inMDNS
);
270 //===========================================================================================================================
272 //===========================================================================================================================
274 void mDNSPlatformClose( mDNS
* const inMDNS
)
282 // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread.
284 if( inMDNS
->p
->taskID
!= ERROR
)
286 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
287 if( inMDNS
->p
->quitEvent
)
289 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
292 inMDNS
->p
->taskID
= ERROR
;
295 // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
297 ForgetSem( &inMDNS
->p
->quitEvent
);
298 ForgetSem( &inMDNS
->p
->initEvent
);
299 ForgetSem( &inMDNS
->p
->lock
);
301 dmsg( kDebugLevelNotice
, DEBUG_NAME
"CLOSED\n" );
304 //===========================================================================================================================
305 // mDNSPlatformSendUDP
306 //===========================================================================================================================
310 const mDNS
* const inMDNS
,
311 const void * const inMsg
,
312 const mDNSu8
* const inEnd
,
313 mDNSInterfaceID inInterfaceID
,
314 const mDNSAddr
* inDstIP
,
315 mDNSIPPort inDstPort
)
318 NetworkInterfaceInfoVxWorks
* info
;
320 struct sockaddr_storage to
;
323 // Set up the sockaddr to sent to and the socket to send on.
325 info
= (NetworkInterfaceInfoVxWorks
*) inInterfaceID
;
326 if( inDstIP
->type
== mDNSAddrType_IPv4
)
328 struct sockaddr_in
* sa4
;
330 sa4
= (struct sockaddr_in
*) &to
;
331 sa4
->sin_len
= sizeof( *sa4
);
332 sa4
->sin_family
= AF_INET
;
333 sa4
->sin_port
= inDstPort
.NotAnInteger
;
334 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
335 sock
= info
? info
->ss
.sockV4
: inMDNS
->p
->unicastSS
.sockV4
;
337 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
339 struct sockaddr_in6
* sa6
;
341 sa6
= (struct sockaddr_in6
*) &to
;
342 sa6
->sin6_len
= sizeof( *sa6
);
343 sa6
->sin6_family
= AF_INET6
;
344 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
345 sa6
->sin6_flowinfo
= 0;
346 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
347 sa6
->sin6_scope_id
= info
? info
->scopeID
: 0;
348 sock
= info
? info
->ss
.sockV6
: inMDNS
->p
->unicastSS
.sockV6
;
352 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__
);
353 err
= mStatus_BadParamErr
;
357 // 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
358 // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error.
360 n
= (int)( (mDNSu8
*) inEnd
- (mDNSu8
*) inMsg
);
361 if( !IsValidSocket( sock
) )
363 dpkt( kDebugLevelChatty
- 1,
364 DEBUG_NAME
"DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
365 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
366 err
= mStatus_Invalid
;
370 dpkt( kDebugLevelChatty
,
371 DEBUG_NAME
"SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
372 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
374 n
= sendto( sock
, (mDNSu8
*) inMsg
, n
, 0, (struct sockaddr
*) &to
, to
.ss_len
);
377 // Don't warn about ARP failures or no route to host for unicast destinations.
379 err
= errno_compat();
380 if( ( ( err
== EHOSTDOWN
) || ( err
== ENETDOWN
) || ( err
== EHOSTUNREACH
) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP
) )
385 dmsg( kDebugLevelError
, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
386 __ROUTINE__
, info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, inDstIP
, mDNSVal16( inDstPort
),
387 sock
, err
, (unsigned int) inMDNS
->timenow
);
388 if( err
== 0 ) err
= mStatus_UnknownErr
;
391 err
= mStatus_NoError
;
397 //===========================================================================================================================
398 // Connection-oriented (TCP) functions
399 //===========================================================================================================================
401 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
402 TCPConnectionCallback callback
, void *context
, int *descriptor
)
405 (void)dstport
; // Unused
406 (void)InterfaceID
; // Unused
407 (void)callback
; // Unused
408 (void)context
; // Unused
409 (void)descriptor
; // Unused
410 return(mStatus_UnsupportedErr
);
413 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
418 mDNSexport
long mDNSPlatformReadTCP(int sd
, void *buf
, unsigned long buflen
)
422 (void)buflen
; // Unused
426 mDNSexport
long mDNSPlatformWriteTCP(int sd
, const char *msg
, unsigned long len
)
434 //===========================================================================================================================
436 //===========================================================================================================================
438 void mDNSPlatformLock( const mDNS
* const inMDNS
)
440 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
443 if( semTake( inMDNS
->p
->lock
, 60 * sysClkRateGet() ) != OK
)
445 dmsg( kDebugLevelTragic
, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS
->p
->lock
, taskIdSelf() );
446 debug_stack_trace(); // 1) Print Stack Trace.
447 semShow( inMDNS
->p
->lock
, 1 ); // 2) Print semaphore info, including which tasks are pending on it.
448 taskSuspend( 0 ); // 3) Suspend task. Can be resumed from the console for debugging.
451 semTake( inMDNS
->p
->lock
, WAIT_FOREVER
);
455 //===========================================================================================================================
456 // mDNSPlatformUnlock
457 //===========================================================================================================================
459 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
461 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
463 // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time.
464 // We only need to wake up if we're not already inside the task. This avoids filling up the command queue.
466 if( taskIdSelf() != inMDNS
->p
->taskID
)
468 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
470 semGive( inMDNS
->p
->lock
);
473 //===========================================================================================================================
474 // mDNSPlatformStrLen
475 //===========================================================================================================================
477 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
481 return( (mDNSu32
) strlen( (const char *) inSrc
) );
484 //===========================================================================================================================
485 // mDNSPlatformStrCopy
486 //===========================================================================================================================
488 void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
493 strcpy( (char *) inDst
, (const char*) inSrc
);
496 //===========================================================================================================================
497 // mDNSPlatformMemCopy
498 //===========================================================================================================================
500 void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
505 memcpy( inDst
, inSrc
, inSize
);
508 //===========================================================================================================================
509 // mDNSPlatformMemSame
510 //===========================================================================================================================
512 mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
517 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
520 //===========================================================================================================================
521 // mDNSPlatformMemZero
522 //===========================================================================================================================
524 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
528 memset( inDst
, 0, inSize
);
531 //===========================================================================================================================
532 // mDNSPlatformMemAllocate
533 //===========================================================================================================================
535 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
541 mem
= malloc( inSize
);
547 //===========================================================================================================================
548 // mDNSPlatformMemFree
549 //===========================================================================================================================
551 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
554 if( inMem
) free( inMem
);
557 //===========================================================================================================================
558 // mDNSPlatformRandomSeed
559 //===========================================================================================================================
561 mDNSexport mDNSu32
mDNSPlatformRandomSeed( void )
566 //===========================================================================================================================
567 // mDNSPlatformTimeInit
568 //===========================================================================================================================
570 mDNSexport mStatus
mDNSPlatformTimeInit( void )
572 // No special setup is required on VxWorks -- we just use tickGet().
574 return( mStatus_NoError
);
577 //===========================================================================================================================
578 // mDNSPlatformRawTime
579 //===========================================================================================================================
581 mDNSs32
mDNSPlatformRawTime( void )
583 return( (mDNSs32
) tickGet() );
586 //===========================================================================================================================
588 //===========================================================================================================================
590 mDNSexport mDNSs32
mDNSPlatformUTC( void )
592 return( (mDNSs32
) time( NULL
) );
595 //===========================================================================================================================
596 // mDNSPlatformInterfaceIDfromInterfaceIndex
597 //===========================================================================================================================
599 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
*const inMDNS
, mDNSu32 inIndex
)
601 NetworkInterfaceInfoVxWorks
* i
;
603 if( inIndex
== (mDNSu32
) -1 ) return( mDNSInterface_LocalOnly
);
606 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
608 // Don't get tricked by inactive interfaces with no InterfaceID set.
610 if( i
->ifinfo
.InterfaceID
&& ( i
->scopeID
== inIndex
) ) return( i
->ifinfo
.InterfaceID
);
616 //===========================================================================================================================
617 // mDNSPlatformInterfaceIndexfromInterfaceID
618 //===========================================================================================================================
620 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
*const inMDNS
, mDNSInterfaceID inID
)
622 NetworkInterfaceInfoVxWorks
* i
;
624 if( inID
== mDNSInterface_LocalOnly
) return( (mDNSu32
) -1 );
627 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
629 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
630 if( i
) return( i
->scopeID
);
635 //===========================================================================================================================
636 // mDNSPlatformInterfaceNameToID
637 //===========================================================================================================================
639 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
641 NetworkInterfaceInfoVxWorks
* i
;
643 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
645 // Don't get tricked by inactive interfaces with no InterfaceID set.
647 if( i
->ifinfo
.InterfaceID
&& ( strcmp( i
->ifinfo
.ifname
, inName
) == 0 ) )
649 *outID
= (mDNSInterfaceID
) i
;
650 return( mStatus_NoError
);
653 return( mStatus_NoSuchNameErr
);
656 //===========================================================================================================================
657 // mDNSPlatformInterfaceIDToInfo
658 //===========================================================================================================================
660 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
662 NetworkInterfaceInfoVxWorks
* i
;
664 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
666 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
667 if( !i
) return( mStatus_NoSuchNameErr
);
669 outInfo
->name
= i
->ifinfo
.ifname
;
670 outInfo
->ip
= i
->ifinfo
.ip
;
671 return( mStatus_NoError
);
674 //===========================================================================================================================
676 //===========================================================================================================================
678 #if( MDNS_DEBUGMSGS > 0 )
679 mDNSexport
void debugf_( const char *inFormat
, ... )
684 va_start( args
, inFormat
);
685 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
688 dlog( kDebugLevelInfo
, "%s\n", buffer
);
692 //===========================================================================================================================
694 //===========================================================================================================================
696 #if( MDNS_DEBUGMSGS > 1 )
697 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
702 va_start( args
, inFormat
);
703 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
706 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
710 //===========================================================================================================================
712 //===========================================================================================================================
714 mDNSexport
void LogMsg( const char *inFormat
, ... )
720 va_start( args
, inFormat
);
721 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
724 dlog( kDebugLevelWarning
, "%s\n", buffer
);
726 DEBUG_UNUSED( inFormat
);
731 //===========================================================================================================================
733 //===========================================================================================================================
735 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... )
740 va_start( args
, inFormat
);
741 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
744 if( inLevel
>= gMDNSDebugOverrideLevel
) inLevel
= kDebugLevelMax
;
745 dlog( inLevel
, "%s", buffer
);
751 #pragma mark == Interfaces ==
754 //===========================================================================================================================
755 // UpdateInterfaceList
756 //===========================================================================================================================
758 #if( MDNS_ENABLE_PPP )
760 // Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
762 #define IsCompatibleInterface( IFA ) \
763 ( ( ( IFA )->ifa_flags & IFF_UP ) && \
764 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
765 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \
766 ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
768 #define IsCompatibleInterface( IFA ) \
769 ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \
770 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
771 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) )
774 #define IsLinkLocalSockAddr( SA ) \
775 ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
776 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
777 ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
778 : IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
780 #define FamilyToString( X ) \
781 ( ( ( X ) == AF_INET ) ? "AF_INET" : \
782 ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
783 ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
786 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
)
789 struct ifaddrs
* ifaList
;
790 struct ifaddrs
* ifa
;
794 struct ifaddrs
* loopbackV4
;
795 struct ifaddrs
* loopbackV6
;
796 mDNSEthAddr primaryMAC
;
798 char defaultName
[ 64 ];
799 NetworkInterfaceInfoVxWorks
* i
;
800 domainlabel nicelabel
;
801 domainlabel hostlabel
;
809 primaryMAC
= zeroEthAddr
;
811 // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
813 infoSock
= socket( AF_INET6
, SOCK_DGRAM
, 0 );
814 check_translated_errno( IsValidSocket( infoSock
), errno_compat(), kUnknownErr
);
816 // Run through the entire list of interfaces.
818 err
= getifaddrs( &ifaList
);
819 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
821 for( ifa
= ifaList
; ifa
; ifa
= ifa
->ifa_next
)
825 family
= ifa
->ifa_addr
->sa_family
;
826 dmsg( kDebugLevelVerbose
, DEBUG_NAME
"%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__
,
827 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), ifa
->ifa_flags
, FamilyToString( family
), family
);
829 // Save off the MAC address of the first Ethernet-ish interface.
831 if( family
== AF_LINK
)
833 struct sockaddr_dl
* sdl
;
835 sdl
= (struct sockaddr_dl
*) ifa
->ifa_addr
;
836 if( ( sdl
->sdl_type
== IFT_ETHER
) && ( sdl
->sdl_alen
== sizeof( primaryMAC
) &&
837 mDNSSameEthAddress( &primaryMAC
, &zeroEthAddr
) ) )
839 memcpy( primaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6 );
843 if( !IsCompatibleInterface( ifa
) ) continue;
845 // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
847 if( IsLinkLocalSockAddr( ifa
->ifa_addr
) )
849 struct ifaddrs
* ifaLL
;
851 for( ifaLL
= ifaList
; ifaLL
; ifaLL
= ifaLL
->ifa_next
)
853 if( ifaLL
->ifa_addr
->sa_family
!= family
) continue;
854 if( !IsCompatibleInterface( ifaLL
) ) continue;
855 if( strcmp( ifaLL
->ifa_name
, ifa
->ifa_name
) != 0 ) continue;
856 if( !IsLinkLocalSockAddr( ifaLL
->ifa_addr
) ) break;
860 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %8s(%d) skipping link-local alias\n", __ROUTINE__
,
861 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
) );
866 // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use.
867 // If this is a loopback interface, save it off since we may add it later if there are no other interfaces.
868 // Otherwise, add the interface to the list.
871 if( ( family
== AF_INET6
) && IsValidSocket( infoSock
) )
873 struct sockaddr_in6
* sa6
;
874 struct in6_ifreq ifr6
;
876 sa6
= (struct sockaddr_in6
*) ifa
->ifa_addr
;
877 mDNSPlatformMemZero( &ifr6
, sizeof( ifr6
) );
878 strcpy( ifr6
.ifr_name
, ifa
->ifa_name
);
879 ifr6
.ifr_addr
= *sa6
;
880 if( ioctl( infoSock
, SIOCGIFAFLAG_IN6
, (int) &ifr6
) != -1 )
882 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
886 // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is
887 // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an
888 // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround,
889 // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks.
891 if( flags
& ( IN6_IFF_DUPLICATED
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
) )
893 dmsg( kDebugLevelNotice
, DEBUG_NAME
"%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__
,
894 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), flags
);
897 if( ifa
->ifa_flags
& IFF_LOOPBACK
)
899 if( family
== AF_INET
) loopbackV4
= ifa
;
900 else loopbackV6
= ifa
;
904 if( ( family
== AF_INET
) && gMDNSDeferIPv4
&& IsLinkLocalSockAddr( ifa
->ifa_addr
) ) continue;
905 i
= AddInterfaceToList( inMDNS
, ifa
, inUTC
);
906 if( i
&& i
->multicast
)
908 if( family
== AF_INET
) foundV4
= mDNStrue
;
909 else foundV6
= mDNStrue
;
914 // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
916 if( !foundV4
&& loopbackV4
) AddInterfaceToList( inMDNS
, loopbackV4
, inUTC
);
917 if( !foundV6
&& loopbackV6
) AddInterfaceToList( inMDNS
, loopbackV6
, inUTC
);
918 freeifaddrs( ifaList
);
919 if( IsValidSocket( infoSock
) ) close_compat( infoSock
);
921 // The list is complete. Set the McastTxRx setting for each interface. We always send and receive using IPv4.
922 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
923 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large, configured network,
924 // which means there's a good chance that most or all the other devices on that network should also have v4.
925 // 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.
926 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
927 // so we are willing to make that sacrifice.
929 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
935 txrx
= i
->multicast
&& ( ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4( inMDNS
, i
->scopeID
) );
936 if( i
->ifinfo
.McastTxRx
!= txrx
)
938 i
->ifinfo
.McastTxRx
= txrx
;
939 i
->exists
= 2; // 2=state change; need to de-register and re-register this interface.
944 // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
946 mDNS_snprintf( defaultName
, sizeof( defaultName
), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
947 primaryMAC
.b
[ 0 ], primaryMAC
.b
[ 1 ], primaryMAC
.b
[ 2 ], primaryMAC
.b
[ 3 ], primaryMAC
.b
[ 4 ], primaryMAC
.b
[ 5 ] );
949 MakeDomainLabelFromLiteralString( &nicelabel
, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
950 if( nicelabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel
, defaultName
);
952 // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
954 MakeDomainLabelFromLiteralString( &tmp
, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device.
955 ConvertUTF8PstringToRFC1034HostLabel( tmp
.c
, &hostlabel
);
956 if( hostlabel
.c
[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel
.c
, &hostlabel
);
957 if( hostlabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel
, defaultName
);
959 // Update our globals and mDNS with the new labels.
961 if( !SameDomainLabelCS( inMDNS
->p
->userNiceLabel
.c
, nicelabel
.c
) )
963 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating nicelabel to \"%#s\"\n", nicelabel
.c
);
964 inMDNS
->p
->userNiceLabel
= nicelabel
;
965 inMDNS
->nicelabel
= nicelabel
;
967 if( !SameDomainLabelCS( inMDNS
->p
->userHostLabel
.c
, hostlabel
.c
) )
969 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating hostlabel to \"%#s\"\n", hostlabel
.c
);
970 inMDNS
->p
->userHostLabel
= hostlabel
;
971 inMDNS
->hostlabel
= hostlabel
;
972 mDNS_SetFQDN( inMDNS
);
974 return( mStatus_NoError
);
977 //===========================================================================================================================
978 // AddInterfaceToList
979 //===========================================================================================================================
981 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
)
987 NetworkInterfaceInfoVxWorks
** p
;
988 NetworkInterfaceInfoVxWorks
* i
;
992 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ip
);
993 require_noerr( err
, exit
);
995 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &mask
);
996 require_noerr( err
, exit
);
998 // Search for an existing interface with the same info. If found, just return that one.
1000 scopeID
= if_nametoindex( inIFA
->ifa_name
);
1002 for( p
= &inMDNS
->p
->interfaceList
; *p
; p
= &( *p
)->next
)
1004 if( ( scopeID
== ( *p
)->scopeID
) && mDNSSameAddress( &ip
, &( *p
)->ifinfo
.ip
) )
1006 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__
,
1008 ( *p
)->exists
= mDNStrue
;
1014 // Allocate the new interface info and fill it out.
1016 i
= (NetworkInterfaceInfoVxWorks
*) calloc( 1, sizeof( *i
) );
1019 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__
, scopeID
, &ip
, i
);
1020 strncpy( i
->ifinfo
.ifname
, inIFA
->ifa_name
, sizeof( i
->ifinfo
.ifname
) );
1021 i
->ifinfo
.ifname
[ sizeof( i
->ifinfo
.ifname
) - 1 ] = '\0';
1022 i
->ifinfo
.InterfaceID
= NULL
;
1024 i
->ifinfo
.mask
= mask
;
1025 i
->ifinfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1026 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList.
1029 i
->exists
= mDNStrue
;
1030 i
->lastSeen
= inUTC
;
1031 i
->scopeID
= scopeID
;
1032 i
->family
= inIFA
->ifa_addr
->sa_family
;
1033 i
->multicast
= ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTOPOINT
);
1036 i
->ss
.sockV4
= kInvalidSocketRef
;
1037 i
->ss
.sockV6
= kInvalidSocketRef
;
1044 //===========================================================================================================================
1045 // SetupActiveInterfaces
1047 // Returns a count of non-link local IPv4 addresses registered.
1048 //===========================================================================================================================
1050 #define mDNSAddressIsNonLinkLocalIPv4( X ) \
1051 ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
1053 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1056 NetworkInterfaceInfoVxWorks
* i
;
1059 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1061 NetworkInterfaceInfo
* n
;
1062 NetworkInterfaceInfoVxWorks
* primary
;
1064 if( !i
->exists
) continue;
1066 // Search for the primary interface and sanity check it.
1069 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1072 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! didn't find %s(%u)\n", __ROUTINE__
, i
->ifinfo
.ifname
, i
->scopeID
);
1075 if( n
->InterfaceID
&& ( n
->InterfaceID
!= (mDNSInterfaceID
) primary
) )
1077 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__
,
1078 n
->InterfaceID
, primary
);
1079 n
->InterfaceID
= NULL
;
1082 // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface.
1083 // so we don't need to call it again. Otherwise, register the interface with mDNS.
1085 if( !n
->InterfaceID
)
1089 n
->InterfaceID
= (mDNSInterfaceID
) primary
;
1091 // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away.
1092 // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds.
1093 // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
1095 flapping
= ( ( inUTC
- i
->lastSeen
) > 0 ) && ( ( inUTC
- i
->lastSeen
) < 60 );
1096 mDNS_RegisterInterface( inMDNS
, n
, flapping
);
1097 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1099 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__
,
1100 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
,
1101 flapping
? " (Flapping)" : "",
1102 n
->InterfaceActive
? " (Primary)" : "" );
1105 // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we
1106 // don't need a socket since unicast traffic will be handled on the unicast socket.
1112 if( ( ( i
->family
== AF_INET
) && !IsValidSocket( primary
->ss
.sockV4
) ) ||
1113 ( ( i
->family
== AF_INET6
) && !IsValidSocket( primary
->ss
.sockV6
) ) )
1115 err
= SetupSocket( inMDNS
, &i
->ifinfo
.ip
, mDNStrue
, i
->family
, &primary
->ss
);
1121 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__
,
1122 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
);
1128 //===========================================================================================================================
1129 // MarkAllInterfacesInactive
1130 //===========================================================================================================================
1132 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1134 NetworkInterfaceInfoVxWorks
* i
;
1136 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1138 if( !i
->exists
) continue;
1139 i
->lastSeen
= inUTC
;
1140 i
->exists
= mDNSfalse
;
1144 //===========================================================================================================================
1145 // ClearInactiveInterfaces
1147 // Returns count of non-link local IPv4 addresses de-registered.
1148 //===========================================================================================================================
1150 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
)
1153 NetworkInterfaceInfoVxWorks
* i
;
1154 NetworkInterfaceInfoVxWorks
** p
;
1157 // If an interface is going away, then de-register it from mDNSCore.
1158 // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away.
1159 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1160 // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though:
1161 // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that
1162 // interface. (Not yet implemented, but a good idea anyway.).
1165 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1167 NetworkInterfaceInfoVxWorks
* primary
;
1169 // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
1171 if( !i
->ifinfo
.InterfaceID
) continue;
1172 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1173 if( ( i
->exists
== 0 ) || ( i
->exists
== 2 ) || ( i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
) primary
) )
1175 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__
,
1176 i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1177 i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1179 mDNS_DeregisterInterface( inMDNS
, &i
->ifinfo
, mDNSfalse
);
1180 i
->ifinfo
.InterfaceID
= NULL
;
1181 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1186 // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
1188 p
= &inMDNS
->p
->interfaceList
;
1193 // 2. Close all our sockets. We'll recreate them later as needed.
1194 // (We may have previously had both v4 and v6, and we may not need both any more.).
1196 ForgetSocket( &i
->ss
.sockV4
);
1197 ForgetSocket( &i
->ss
.sockV6
);
1199 // 3. If no longer active, remove the interface from the list and free its memory.
1207 check_string( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0, "closing with in-use records!" );
1208 deleteIt
= mDNStrue
;
1212 if( i
->lastSeen
== inUTC
) i
->lastSeen
= inUTC
- 1;
1213 deleteIt
= ( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0 ) && ( ( inUTC
- i
->lastSeen
) >= 60 );
1215 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__
,
1216 deleteIt
? "Deleting" : "Holding", i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1217 inUTC
- i
->lastSeen
, i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1230 //===========================================================================================================================
1232 //===========================================================================================================================
1234 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
)
1236 #if( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1237 NetworkInterfaceInfoVxWorks
* i
;
1239 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1241 if( i
->exists
&& ( i
->scopeID
== inScopeID
) && mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) )
1248 DEBUG_UNUSED( inMDNS
);
1249 DEBUG_UNUSED( inScopeID
);
1255 //===========================================================================================================================
1256 // FindInterfaceByIndex
1257 //===========================================================================================================================
1259 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
)
1261 NetworkInterfaceInfoVxWorks
* i
;
1263 check( inIndex
!= 0 );
1265 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1267 if( i
->exists
&& ( i
->scopeID
== inIndex
) &&
1268 ( MDNS_AAAA_OVER_IPV4
||
1269 ( ( inFamily
== AF_INET
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ) ||
1270 ( ( inFamily
== AF_INET6
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) ) ) )
1278 //===========================================================================================================================
1280 //===========================================================================================================================
1282 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
)
1285 SocketRef
* sockPtr
;
1293 sockPtr
= ( inFamily
== AF_INET
) ? &inSS
->sockV4
: &inSS
->sockV6
;
1294 port
= ( inMcast
|| inMDNS
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1296 sock
= socket( inFamily
, SOCK_DGRAM
, IPPROTO_UDP
);
1297 err
= translate_errno( IsValidSocket( sock
), errno_compat(), mStatus_UnknownErr
);
1298 require_noerr( err
, exit
);
1300 // Allow multiple listeners if this is a multicast port.
1302 if( port
.NotAnInteger
)
1304 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEPORT
, (char *) &on
, sizeof( on
) );
1305 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1308 // Set up the socket based on the family (IPv4 or IPv6).
1310 if( inFamily
== AF_INET
)
1312 const int ttlV4
= 255;
1313 const u_char ttlV4Mcast
= 255;
1314 struct sockaddr_in sa4
;
1316 // Receive destination addresses so we know which address the packet was sent to.
1318 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVDSTADDR
, (char *) &on
, sizeof( on
) );
1319 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1321 // Receive interface indexes so we know which interface received the packet.
1323 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVIF
, (char *) &on
, sizeof( on
) );
1324 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1326 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1330 struct in_addr addrV4
;
1331 struct ip_mreq mreqV4
;
1333 addrV4
.s_addr
= inAddr
->ip
.v4
.NotAnInteger
;
1334 mreqV4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1335 mreqV4
.imr_interface
= addrV4
;
1336 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqV4
, sizeof( mreqV4
) );
1337 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1339 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addrV4
, sizeof( addrV4
) );
1340 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1343 // Send unicast packets with TTL 255 (helps against spoofing).
1345 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &ttlV4
, sizeof( ttlV4
) );
1346 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1348 // Send multicast packets with TTL 255 (helps against spoofing).
1350 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &ttlV4Mcast
, sizeof( ttlV4Mcast
) );
1351 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1353 // Start listening for packets.
1355 mDNSPlatformMemZero( &sa4
, sizeof( sa4
) );
1356 sa4
.sin_len
= sizeof( sa4
);
1357 sa4
.sin_family
= AF_INET
;
1358 sa4
.sin_port
= port
.NotAnInteger
;
1359 sa4
.sin_addr
.s_addr
= htonl( INADDR_ANY
); // We want to receive multicasts AND unicasts on this socket.
1360 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
1361 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1363 else if( inFamily
== AF_INET6
)
1365 struct sockaddr_in6 sa6
;
1366 const int ttlV6
= 255;
1368 // Receive destination addresses and interface index so we know where the packet was received and intended.
1370 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &on
, sizeof( on
) );
1371 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1373 // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
1375 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &on
, sizeof( on
) );
1376 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1378 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1383 struct ipv6_mreq mreqV6
;
1385 ifindex
= inSS
->info
->scopeID
;
1386 mreqV6
.ipv6mr_interface
= ifindex
;
1387 mreqV6
.ipv6mr_multiaddr
= *( (struct in6_addr
* ) &AllDNSLinkGroup_v6
.ip
.v6
);
1388 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqV6
, sizeof( mreqV6
) );
1389 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1391 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &ifindex
, sizeof( ifindex
) );
1392 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1395 // Send unicast packets with TTL 255 (helps against spoofing).
1397 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1398 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1400 // Send multicast packets with TTL 255 (helps against spoofing).
1402 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1403 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1405 // Receive our own packets for same-machine operation.
1407 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &on
, sizeof( on
) );
1408 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1410 // Start listening for packets.
1412 mDNSPlatformMemZero( &sa6
, sizeof( sa6
) );
1413 sa6
.sin6_len
= sizeof( sa6
);
1414 sa6
.sin6_family
= AF_INET6
;
1415 sa6
.sin6_port
= port
.NotAnInteger
;
1416 sa6
.sin6_flowinfo
= 0;
1417 sa6
.sin6_addr
= in6addr_any
; // We want to receive multicasts AND unicasts on this socket.
1418 sa6
.sin6_scope_id
= 0;
1419 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
1420 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1424 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inFamily
);
1425 err
= kUnsupportedErr
;
1429 // Make the socket non-blocking so we can potentially get multiple packets per select call.
1431 err
= ioctl( sock
, FIONBIO
, (int) &on
);
1432 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1435 sock
= kInvalidSocketRef
;
1436 err
= mStatus_NoError
;
1439 if( IsValidSocket( sock
) ) close_compat( sock
);
1443 //===========================================================================================================================
1444 // SockAddrToMDNSAddr
1445 //===========================================================================================================================
1447 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
)
1454 if( inSA
->sa_family
== AF_INET
)
1456 struct sockaddr_in
* sa4
;
1458 sa4
= (struct sockaddr_in
*) inSA
;
1459 outIP
->type
= mDNSAddrType_IPv4
;
1460 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1461 err
= mStatus_NoError
;
1463 else if( inSA
->sa_family
== AF_INET6
)
1465 struct sockaddr_in6
* sa6
;
1467 sa6
= (struct sockaddr_in6
*) inSA
;
1468 outIP
->type
= mDNSAddrType_IPv6
;
1469 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1470 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) ) outIP
->ip
.v6
.w
[ 1 ] = 0;
1471 err
= mStatus_NoError
;
1475 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family (%d)\n", __ROUTINE__
, inSA
->sa_family
);
1476 err
= mStatus_BadParamErr
;
1483 #pragma mark == Commands ==
1486 //===========================================================================================================================
1488 //===========================================================================================================================
1490 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1494 err
= pipeDevCreate( "/pipe/mDNS", 32, 1 );
1495 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1497 inMDNS
->p
->commandPipe
= open( "/pipe/mDNS", O_RDWR
, 0 );
1498 err
= translate_errno( inMDNS
->p
->commandPipe
!= ERROR
, errno_compat(), mStatus_UnsupportedErr
);
1499 require_noerr( err
, exit
);
1505 //===========================================================================================================================
1506 // TearDownCommandPipe
1507 //===========================================================================================================================
1509 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1513 if( inMDNS
->p
->commandPipe
!= ERROR
)
1515 err
= close( inMDNS
->p
->commandPipe
);
1516 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1517 inMDNS
->p
->commandPipe
= ERROR
;
1519 err
= pipeDevDelete( "/pipe/mDNS", FALSE
);
1520 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1522 return( mStatus_NoError
);
1525 //===========================================================================================================================
1527 //===========================================================================================================================
1529 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1533 require_action_quiet( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1535 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1536 err
= translate_errno( err
>= 0, errno_compat(), kWriteErr
);
1537 require_noerr( err
, exit
);
1543 //===========================================================================================================================
1545 //===========================================================================================================================
1547 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1550 MDNSPipeCommandCode cmd
;
1553 err
= read( inMDNS
->p
->commandPipe
, &cmd
, sizeof( cmd
) );
1554 err
= translate_errno( err
>= 0, errno_compat(), kReadErr
);
1555 require_noerr( err
, exit
);
1559 case kMDNSPipeCommandCodeReschedule
: // Reschedule: just break out to re-run mDNS_Execute.
1562 case kMDNSPipeCommandCodeReconfigure
: // Reconfigure: rebuild the interface list after a config change.
1563 dmsg( kDebugLevelInfo
, DEBUG_NAME
"*** NETWORK CONFIGURATION CHANGE ***\n" );
1564 mDNSPlatformLock( inMDNS
);
1566 utc
= mDNSPlatformUTC();
1567 MarkAllInterfacesInactive( inMDNS
, utc
);
1568 UpdateInterfaceList( inMDNS
, utc
);
1569 ClearInactiveInterfaces( inMDNS
, utc
, mDNSfalse
);
1570 SetupActiveInterfaces( inMDNS
, utc
);
1572 mDNSPlatformUnlock( inMDNS
);
1573 mDNS_ConfigChanged(inMDNS
);
1576 case kMDNSPipeCommandCodeQuit
: // Quit: just set a flag so the task exits cleanly.
1577 inMDNS
->p
->quit
= mDNStrue
;
1581 dmsg( kDebugLevelError
, DEBUG_NAME
"unknown pipe command (%d)\n", cmd
);
1582 err
= mStatus_BadParamErr
;
1592 #pragma mark == Threads ==
1595 //===========================================================================================================================
1597 //===========================================================================================================================
1599 mDNSlocal
void Task( mDNS
*inMDNS
)
1605 struct timeval timeout
;
1606 NetworkInterfaceInfoVxWorks
* i
;
1612 err
= TaskInit( inMDNS
);
1613 require_noerr( err
, exit
);
1615 while( !inMDNS
->p
->quit
)
1617 // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
1619 nextEvent
= mDNS_Execute( inMDNS
);
1620 TaskSetupSelect( inMDNS
, &readSet
, &maxFd
, nextEvent
, &timeout
);
1621 n
= select( maxFd
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1622 check_translated_errno( n
>= 0, errno_compat(), kUnknownErr
);
1623 if( n
== 0 ) continue;
1625 // Process interface-specific sockets with pending data.
1628 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1631 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1633 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1637 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1639 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1644 // Process unicast sockets with pending data.
1646 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1647 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1649 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1652 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1653 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1655 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1659 // Processing pending commands.
1661 fd
= inMDNS
->p
->commandPipe
;
1663 if( FD_ISSET( fd
, &readSet
) )
1665 ProcessCommand( inMDNS
);
1668 check_string( n
> 0, "select said something was readable, but nothing was" );
1675 //===========================================================================================================================
1677 //===========================================================================================================================
1679 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1685 inMDNS
->p
->taskID
= taskIdSelf();
1687 err
= SetupCommandPipe( inMDNS
);
1688 require_noerr( err
, exit
);
1690 inMDNS
->CanReceiveUnicastOn5353
= mDNStrue
;
1692 // Set up the HINFO string using the description property (e.g. "Device V1.0").
1694 inMDNS
->HIHardware
.c
[ 0 ] = 11;
1695 memcpy( &inMDNS
->HIHardware
.c
[ 1 ], "Device V1.0", inMDNS
->HIHardware
.c
[ 0 ] ); // $$$ Implementers: Fill in real info.
1697 // Set up the unicast sockets.
1699 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET
, &inMDNS
->p
->unicastSS
);
1701 if( err
== mStatus_NoError
)
1703 struct sockaddr_in sa4
;
1705 len
= sizeof( sa4
);
1706 err
= getsockname( inMDNS
->p
->unicastSS
.sockV4
, (struct sockaddr
*) &sa4
, &len
);
1707 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1708 if( err
== 0 ) inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
1711 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET6
, &inMDNS
->p
->unicastSS
);
1713 if( err
== mStatus_NoError
)
1715 struct sockaddr_in6 sa6
;
1717 len
= sizeof( sa6
);
1718 err
= getsockname( inMDNS
->p
->unicastSS
.sockV6
, (struct sockaddr
*) &sa6
, &len
);
1719 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1720 if( err
== 0 ) inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
1723 // Set up the interfaces.
1725 utc
= mDNSPlatformUTC();
1726 UpdateInterfaceList( inMDNS
, utc
);
1727 SetupActiveInterfaces( inMDNS
, utc
);
1728 err
= mStatus_NoError
;
1731 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1733 inMDNS
->p
->initErr
= err
;
1734 semGive( inMDNS
->p
->initEvent
);
1738 //===========================================================================================================================
1740 //===========================================================================================================================
1742 mDNSlocal
void TaskTerm( mDNS
*inMDNS
)
1747 // Tear down all interfaces.
1749 utc
= mDNSPlatformUTC();
1750 MarkAllInterfacesInactive( inMDNS
, utc
);
1751 ClearInactiveInterfaces( inMDNS
, utc
, mDNStrue
);
1752 check_string( !inMDNS
->p
->interfaceList
, "LEAK: closing without deleting all interfaces" );
1754 // Close unicast sockets.
1756 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV4
);
1757 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV6
);
1759 // Tear down everything else that was set up in TaskInit then signal back that we're done.
1761 err
= TearDownCommandPipe( inMDNS
);
1764 err
= semGive( inMDNS
->p
->quitEvent
);
1765 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1768 //===========================================================================================================================
1770 //===========================================================================================================================
1772 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
)
1774 NetworkInterfaceInfoVxWorks
* i
;
1782 // Add the interface-specific sockets.
1784 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1787 if( IsValidSocket( fd
) )
1789 FD_SET( fd
, outSet
);
1790 if( fd
> maxFd
) maxFd
= fd
;
1794 if( IsValidSocket( fd
) )
1796 FD_SET( fd
, outSet
);
1797 if( fd
> maxFd
) maxFd
= fd
;
1801 // Add the unicast sockets.
1803 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1804 if( IsValidSocket( fd
) )
1806 FD_SET( fd
, outSet
);
1807 if( fd
> maxFd
) maxFd
= fd
;
1810 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1811 if( IsValidSocket( fd
) )
1813 FD_SET( fd
, outSet
);
1814 if( fd
> maxFd
) maxFd
= fd
;
1817 // Add the command pipe.
1819 fd
= inMDNS
->p
->commandPipe
;
1821 FD_SET( fd
, outSet
);
1822 if( fd
> maxFd
) maxFd
= fd
;
1827 // Calculate how long to wait before performing idle processing.
1829 delta
= inNextEvent
- mDNS_TimeNow( inMDNS
);
1832 // The next task time is now or in the past. Set the timeout to fire immediately.
1834 outTimeout
->tv_sec
= 0;
1835 outTimeout
->tv_usec
= 0;
1839 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1840 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1842 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1843 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicro
;
1844 if( outTimeout
->tv_usec
>= 1000000L )
1846 outTimeout
->tv_sec
+= 1;
1847 outTimeout
->tv_usec
= 0;
1852 //===========================================================================================================================
1853 // TaskProcessPackets
1854 //===========================================================================================================================
1856 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
)
1862 struct sockaddr_storage from
;
1865 mDNSAddr senderAddr
;
1866 mDNSIPPort senderPort
;
1869 buf
= (mDNSu8
*) &inMDNS
->imsg
;
1870 size
= sizeof( inMDNS
->imsg
);
1874 n
= mDNSRecvMsg( inSock
, buf
, size
, &from
, sizeof( from
), &fromSize
, &destAddr
, &ifindex
);
1876 if( from
.ss_family
== AF_INET
)
1878 struct sockaddr_in
* sa4
;
1880 sa4
= (struct sockaddr_in
*) &from
;
1881 senderAddr
.type
= mDNSAddrType_IPv4
;
1882 senderAddr
.ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1883 senderPort
.NotAnInteger
= sa4
->sin_port
;
1885 else if( from
.ss_family
== AF_INET6
)
1887 struct sockaddr_in6
* sa6
;
1889 sa6
= (struct sockaddr_in6
*) &from
;
1890 senderAddr
.type
= mDNSAddrType_IPv6
;
1891 senderAddr
.ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1892 senderPort
.NotAnInteger
= sa6
->sin6_port
;
1896 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: WARNING! from addr unknown family %d\n", __ROUTINE__
, from
.ss_family
);
1900 // Even though we indicated a specific interface when joining the multicast group, a weirdness of the
1901 // sockets API means that even though this socket has only officially joined the multicast group
1902 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1903 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1904 // To work around this weirdness, we use the IP_RECVIF/IPV6_PKTINFO options to find the interface
1905 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1907 if( mDNSAddrIsDNSMulticast( &destAddr
) )
1909 if( !inSS
->info
|| !inSS
->info
->exists
)
1911 dpkt( kDebugLevelChatty
- 3, DEBUG_NAME
" ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
1912 &senderAddr
, &destAddr
, inSock
);
1915 if( ifindex
!= inSS
->info
->scopeID
)
1917 #if( DEBUG && MDNS_DEBUG_PACKETS )
1918 char ifname
[ IF_NAMESIZE
];
1921 dpkt( kDebugLevelChatty
- 3,
1922 DEBUG_NAME
" ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n",
1923 &senderAddr
, &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
,
1924 if_indextoname( ifindex
, ifname
), ifindex
);
1928 id
= inSS
->info
->ifinfo
.InterfaceID
;
1929 dpkt( kDebugLevelChatty
- 2, DEBUG_NAME
"recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n",
1930 n
, &senderAddr
, mDNSVal16( senderPort
), &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
, id
);
1934 NetworkInterfaceInfoVxWorks
* i
;
1936 // For unicast packets, try to find the matching interface.
1938 for( i
= inMDNS
->p
->interfaceList
; i
&& ( i
->scopeID
!= ifindex
); i
= i
->next
) {}
1939 if( i
) id
= i
->ifinfo
.InterfaceID
;
1942 mDNSCoreReceive( inMDNS
, buf
, buf
+ n
, &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, id
);
1946 //===========================================================================================================================
1948 //===========================================================================================================================
1954 size_t inBufferSize
,
1957 size_t * outFromSize
,
1958 mDNSAddr
* outDstAddr
,
1959 uint32_t * outIndex
)
1964 char ancillary
[ 1024 ];
1965 struct cmsghdr
* cmPtr
;
1968 // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
1970 iov
.iov_base
= (char *) inBuffer
;
1971 iov
.iov_len
= inBufferSize
;
1972 msg
.msg_name
= (caddr_t
) outFrom
;
1973 msg
.msg_namelen
= inFromSize
;
1976 msg
.msg_control
= (caddr_t
) &ancillary
;
1977 msg
.msg_controllen
= sizeof( ancillary
);
1979 n
= recvmsg( inSock
, &msg
, 0 );
1982 err
= errno_compat();
1983 if( err
!= EWOULDBLOCK
) dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) returned %d, errno %d\n",
1984 __ROUTINE__
, inSock
, n
, err
);
1987 if( msg
.msg_controllen
< sizeof( struct cmsghdr
) )
1989 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
1990 __ROUTINE__
, inSock
, msg
.msg_controllen
, sizeof( struct cmsghdr
) );
1991 n
= mStatus_UnknownErr
;
1994 if( msg
.msg_flags
& MSG_CTRUNC
)
1996 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__
, inSock
, n
);
1997 n
= mStatus_BadFlagsErr
;
2000 *outFromSize
= msg
.msg_namelen
;
2002 // Parse each option out of the ancillary data.
2004 for( cmPtr
= CMSG_FIRSTHDR( &msg
); cmPtr
; cmPtr
= CMSG_NXTHDR( &msg
, cmPtr
) )
2006 if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVDSTADDR
) )
2008 outDstAddr
->type
= mDNSAddrType_IPv4
;
2009 outDstAddr
->ip
.v4
.NotAnInteger
= *( (mDNSu32
*) CMSG_DATA( cmPtr
) );
2011 else if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVIF
) )
2013 struct sockaddr_dl
* sdl
;
2015 sdl
= (struct sockaddr_dl
*) CMSG_DATA( cmPtr
);
2016 *outIndex
= sdl
->sdl_index
;
2018 else if( ( cmPtr
->cmsg_level
== IPPROTO_IPV6
) && ( cmPtr
->cmsg_type
== IPV6_PKTINFO
) )
2020 struct in6_pktinfo
* pi6
;
2022 pi6
= (struct in6_pktinfo
*) CMSG_DATA( cmPtr
);
2023 outDstAddr
->type
= mDNSAddrType_IPv6
;
2024 outDstAddr
->ip
.v6
= *( (mDNSv6Addr
*) &pi6
->ipi6_addr
);
2025 *outIndex
= pi6
->ipi6_ifindex
;
2035 #pragma mark == Debugging ==
2038 #if( DEBUG && MDNS_DEBUG_SHOW )
2039 //===========================================================================================================================
2041 //===========================================================================================================================
2043 void mDNSShow( void );
2045 void mDNSShow( void )
2047 NetworkInterfaceInfoVxWorks
* i
;
2054 dmsg( kDebugLevelMax
, "\n-- mDNS globals --\n" );
2055 dmsg( kDebugLevelMax
, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2056 dmsg( kDebugLevelMax
, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2057 dmsg( kDebugLevelMax
, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2058 dmsg( kDebugLevelMax
, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2059 dmsg( kDebugLevelMax
, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond
);
2060 dmsg( kDebugLevelMax
, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro
);
2061 dmsg( kDebugLevelMax
, " gMDNSPtr = %#p\n", gMDNSPtr
);
2064 dmsg( kDebugLevelMax
, "### mDNS not initialized\n" );
2067 dmsg( kDebugLevelMax
, " nicelabel = \"%#s\"\n", gMDNSPtr
->nicelabel
.c
);
2068 dmsg( kDebugLevelMax
, " hostLabel = \"%#s\"\n", gMDNSPtr
->hostlabel
.c
);
2069 dmsg( kDebugLevelMax
, " MulticastHostname = \"%##s\"\n", gMDNSPtr
->MulticastHostname
.c
);
2070 dmsg( kDebugLevelMax
, " HIHardware = \"%#s\"\n", gMDNSPtr
->HIHardware
.c
);
2071 dmsg( kDebugLevelMax
, " HISoftware = \"%#s\"\n", gMDNSPtr
->HISoftware
.c
);
2072 dmsg( kDebugLevelMax
, " UnicastPort4/6 = %d/%d\n",
2073 mDNSVal16( gMDNSPtr
->UnicastPort4
), mDNSVal16( gMDNSPtr
->UnicastPort6
) );
2074 dmsg( kDebugLevelMax
, " unicastSS.sockV4/V6 = %d/%d\n",
2075 gMDNSPtr
->p
->unicastSS
.sockV4
, gMDNSPtr
->p
->unicastSS
.sockV6
);
2076 dmsg( kDebugLevelMax
, " lock = %#p\n", gMDNSPtr
->p
->lock
);
2077 dmsg( kDebugLevelMax
, " initEvent = %#p\n", gMDNSPtr
->p
->initEvent
);
2078 dmsg( kDebugLevelMax
, " initErr = %ld\n", gMDNSPtr
->p
->initErr
);
2079 dmsg( kDebugLevelMax
, " quitEvent = %#p\n", gMDNSPtr
->p
->quitEvent
);
2080 dmsg( kDebugLevelMax
, " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2081 dmsg( kDebugLevelMax
, " taskID = %#p\n", gMDNSPtr
->p
->taskID
);
2082 dmsg( kDebugLevelMax
, "\n" );
2086 utc
= mDNSPlatformUTC();
2087 dmsg( kDebugLevelMax
, "-- mDNS interfaces --\n" );
2089 for( i
= gMDNSPtr
->p
->interfaceList
; i
; i
= i
->next
)
2091 dmsg( kDebugLevelMax
, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
2092 num
, i
->ifinfo
.ifname
, i
->scopeID
, &i
->ifinfo
.ip
,
2093 i
->ifinfo
.InterfaceID
? " REGISTERED" : "*NOT* registered",
2094 i
->ss
.sockV4
, i
->ss
.sockV6
, utc
- i
->lastSeen
);
2097 dmsg( kDebugLevelMax
, "\n" );
2101 dmsg( kDebugLevelMax
, "-- mDNS resource records --\n" );
2103 for( r
= gMDNSPtr
->ResourceRecords
; r
; r
= r
->next
)
2105 i
= (NetworkInterfaceInfoVxWorks
*) r
->resrec
.InterfaceID
;
2106 if( r
->resrec
.rrtype
== kDNSType_TXT
)
2114 rd
= &r
->resrec
.rdata
->u
;
2115 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num
, i
,
2116 i
? i
->ifinfo
.ifname
: "<any>",
2118 r
->resrec
.rdlength
, r
->resrec
.name
->c
, DNSTypeName( r
->resrec
.rrtype
) );
2122 end
= txt
+ r
->resrec
.rdlength
;
2126 if( ( txt
+ size
) > end
)
2128 dmsg( kDebugLevelMax
, " ### ERROR! txt length byte too big (%u, %u max)\n", size
, end
- txt
);
2131 dmsg( kDebugLevelMax
, " string %2d (%3d bytes): \"%.*s\"\n", nEntries
, size
, size
, txt
);
2138 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %s\n", num
, i
,
2139 i
? i
->ifinfo
.ifname
: "<any>",
2141 ARDisplayString( gMDNSPtr
, r
) );
2145 dmsg( kDebugLevelMax
, "\n");
2147 #endif // DEBUG && MDNS_DEBUG_SHOW