2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Contains: mDNS platform plugin for VxWorks.
25 Copyright: Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
27 Change History (most recent first):
29 $Log: mDNSVxWorks.c,v $
30 Revision 1.26 2004/10/28 02:00:35 cheshire
31 <rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
33 Revision 1.25 2004/10/16 00:17:01 cheshire
34 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
36 Revision 1.24 2004/09/21 21:02:56 cheshire
37 Set up ifname before calling mDNS_RegisterInterface()
39 Revision 1.23 2004/09/17 01:08:57 cheshire
40 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
41 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
42 declared in that file are ONLY appropriate to single-address-space embedded applications.
43 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
45 Revision 1.22 2004/09/17 00:19:11 cheshire
46 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
48 Revision 1.21 2004/09/16 00:24:50 cheshire
49 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
51 Revision 1.20 2004/09/14 23:42:36 cheshire
52 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
54 Revision 1.19 2004/09/14 23:16:09 cheshire
55 mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
57 Revision 1.18 2004/08/14 03:22:42 cheshire
58 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
59 Add GetUserSpecifiedDDNSName() routine
60 Convert ServiceRegDomain to domainname instead of C string
61 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
63 Revision 1.17 2004/07/29 19:26:03 ksekar
64 Plaform-level changes for NATPMP support
66 Revision 1.16 2004/04/22 05:11:28 bradley
67 Added mDNSPlatformUTC for TSIG signed dynamic updates.
69 Revision 1.15 2004/04/21 02:49:12 cheshire
70 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
72 Revision 1.14 2004/04/09 17:43:04 cheshire
73 Make sure to set the McastTxRx field so that duplicate suppression works correctly
75 Revision 1.13 2004/01/27 20:15:24 cheshire
76 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
78 Revision 1.12 2004/01/24 09:12:37 bradley
79 Avoid TOS socket options to workaround a TOS routing problem with VxWorks and multiple interfaces
80 when sending unicast responses, which resulted in packets going out the wrong interface.
82 Revision 1.11 2004/01/24 04:59:16 cheshire
83 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
85 Revision 1.10 2003/11/14 21:27:09 cheshire
86 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
87 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
89 Revision 1.9 2003/11/14 20:59:09 cheshire
90 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
91 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
93 Revision 1.8 2003/10/28 10:08:27 bradley
94 Removed legacy port 53 support as it is no longer needed.
96 Revision 1.7 2003/08/20 05:58:54 bradley
97 Removed dependence on modified mDNSCore: define structures/prototypes locally.
99 Revision 1.6 2003/08/18 23:19:05 cheshire
100 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
102 Revision 1.5 2003/08/15 00:05:04 bradley
103 Updated to use name/InterfaceID from new AuthRecord resrec field. Added output of new record sizes.
105 Revision 1.4 2003/08/14 02:19:55 cheshire
106 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
108 Revision 1.3 2003/08/12 19:56:27 cheshire
111 Revision 1.2 2003/08/05 23:58:34 cheshire
112 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
113 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
115 Revision 1.1 2003/08/02 10:06:48 bradley
116 mDNS platform plugin for VxWorks.
119 Notes for non-Apple platforms:
121 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
125 - Add support for IPv6 (needs VxWorks IPv6 support).
128 // Set up the debug library to use the default category (see DebugServicesLite.h for details).
130 #if( !TARGET_NON_APPLE )
131 #define DEBUG_USE_DEFAULT_CATEGORY 1
140 #include <sys/types.h>
141 #include <arpa/inet.h>
143 #include <netinet/if_ether.h>
144 #include <netinet/in.h>
145 #include <netinet/ip.h>
146 #include <sys/ioctl.h>
147 #include <sys/socket.h>
154 #include "selectLib.h"
163 #if( !TARGET_NON_APPLE )
164 #include "ACP/ACPUtilities.h"
165 #include "Support/DebugServicesLite.h"
166 #include "Support/MiscUtilities.h"
169 #include "mDNSEmbeddedAPI.h"
171 #include "mDNSVxWorks.h"
174 #pragma mark == Preprocessor ==
177 //===========================================================================================================================
179 //===========================================================================================================================
181 #if( !TARGET_NON_APPLE )
182 debug_log_new_default_category( mdns
);
186 #pragma mark == Constants ==
189 //===========================================================================================================================
191 //===========================================================================================================================
193 #define DEBUG_NAME "[mDNS] "
195 #define kMDNSDefaultName "My-Device"
197 #define kMDNSTaskName "tMDNS"
198 #define kMDNSTaskPriority 102
199 #define kMDNSTaskStackSize 49152
201 #define kMDNSPipeName "/pipe/mDNS"
202 #define kMDNSPipeMessageQueueSize 32
203 #define kMDNSPipeMessageSize 1
205 #define kInvalidSocketRef -1
207 typedef uint8_t MDNSPipeCommandCode
;
210 kMDNSPipeCommandCodeInvalid
= 0,
211 kMDNSPipeCommandCodeReschedule
= 1,
212 kMDNSPipeCommandCodeReconfigure
= 2,
213 kMDNSPipeCommandCodeQuit
= 3
217 #pragma mark == Structures ==
220 //===========================================================================================================================
222 //===========================================================================================================================
224 typedef int MDNSSocketRef
;
226 struct MDNSInterfaceItem
228 MDNSInterfaceItem
* next
;
230 MDNSSocketRef multicastSocketRef
;
231 MDNSSocketRef sendingSocketRef
;
232 NetworkInterfaceInfo hostSet
;
233 mDNSBool hostRegistered
;
235 int sendMulticastCounter
;
236 int sendUnicastCounter
;
237 int sendErrorCounter
;
240 int recvErrorCounter
;
245 #pragma mark == Macros ==
248 //===========================================================================================================================
250 //===========================================================================================================================
252 #if( TARGET_NON_APPLE )
254 // Do-nothing versions of the debugging macros for non-Apple platforms.
256 #define check(assertion)
257 #define check_string( assertion, cstring )
258 #define check_noerr(err)
259 #define check_noerr_string( error, cstring )
260 #define check_errno( assertion, errno_value )
261 #define debug_string( cstring )
262 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
263 #define require_string( assertion, label, string ) require(assertion, label)
264 #define require_quiet( assertion, label ) require( assertion, label )
265 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
266 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
267 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
268 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
269 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
270 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
271 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
272 #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label; } while(0)
273 #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
275 #define dlog( ARGS... )
277 #define DEBUG_UNUSED( X ) (void)( X )
281 #pragma mark == Prototypes ==
284 //===========================================================================================================================
286 //===========================================================================================================================
288 // ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
290 extern struct ifnet
* ifIndexToIfp(int ifIndex
);
292 // Platform Internals
294 mDNSlocal
void SetupNames( mDNS
* const inMDNS
);
295 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
296 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
297 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
);
298 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
);
302 const struct ifaddrs
* inAddr
,
304 MDNSSocketRef
* outSocketRef
);
308 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
309 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
310 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
311 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
312 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
);
316 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
);
317 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
);
318 mDNSlocal
void Task( mDNS
*inMDNS
);
319 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
320 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
);
321 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
);
322 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
);
326 #if( TARGET_NON_APPLE )
327 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
);
328 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
);
331 // Platform Accessors
337 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
338 struct mDNSPlatformInterfaceInfo
344 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
345 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
352 #pragma mark == Globals ==
355 //===========================================================================================================================
357 //===========================================================================================================================
359 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
360 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
361 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier
= 0;
365 mDNSs32 mDNSPlatformOneSecond
;
369 #pragma mark == Public APIs ==
372 //===========================================================================================================================
374 //===========================================================================================================================
376 void mDNSReconfigure( void )
378 // Send a "reconfigure" command to the MDNS task.
382 SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
388 #pragma mark == Platform Support ==
391 //===========================================================================================================================
393 //===========================================================================================================================
395 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
399 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init\n" );
401 // Initialize variables.
403 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
404 inMDNS
->p
= &gMDNSPlatformSupport
;
405 inMDNS
->p
->commandPipe
= ERROR
;
406 inMDNS
->p
->task
= ERROR
;
407 inMDNS
->p
->rescheduled
= 1; // Default to rescheduled until fully initialized.
408 mDNSPlatformOneSecond
= sysClkRateGet();
409 gMDNSTicksToMicrosecondsMultiplier
= ( 1000000L / mDNSPlatformOneSecond
);
411 // Allocate semaphores.
413 inMDNS
->p
->lockID
= semMCreate( SEM_Q_FIFO
);
414 require_action( inMDNS
->p
->lockID
, exit
, err
= mStatus_NoMemoryErr
);
416 inMDNS
->p
->readyEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
417 require_action( inMDNS
->p
->readyEvent
, exit
, err
= mStatus_NoMemoryErr
);
419 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
420 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
424 // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
425 // stack space issues. Some of the initialization may require a larger stack than the current task supports.
427 err
= SetupTask( inMDNS
);
428 require_noerr( err
, exit
);
430 err
= semTake( inMDNS
->p
->readyEvent
, WAIT_FOREVER
);
431 require_noerr( err
, exit
);
432 err
= inMDNS
->p
->taskInitErr
;
433 require_noerr( err
, exit
);
435 mDNSCoreInitComplete( inMDNS
, err
);
440 mDNSPlatformClose( inMDNS
);
442 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
446 //===========================================================================================================================
448 //===========================================================================================================================
450 void mDNSPlatformClose( mDNS
* const inMDNS
)
454 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close\n" );
457 // Tear everything down.
459 err
= TearDownTask( inMDNS
);
462 err
= TearDownInterfaceList( inMDNS
);
465 err
= TearDownCommandPipe( inMDNS
);
470 // Release semaphores.
472 if( inMDNS
->p
->quitEvent
)
474 semDelete( inMDNS
->p
->quitEvent
);
475 inMDNS
->p
->quitEvent
= 0;
477 if( inMDNS
->p
->readyEvent
)
479 semDelete( inMDNS
->p
->readyEvent
);
480 inMDNS
->p
->readyEvent
= 0;
482 if( inMDNS
->p
->lockID
)
484 semDelete( inMDNS
->p
->lockID
);
485 inMDNS
->p
->lockID
= 0;
488 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close done\n" );
491 //===========================================================================================================================
492 // mDNSPlatformSendUDP
493 //===========================================================================================================================
497 const mDNS
* const inMDNS
,
498 const void * const inMsg
,
499 const mDNSu8
* const inMsgEnd
,
500 mDNSInterfaceID inInterfaceID
,
501 const mDNSAddr
* inDstIP
,
502 mDNSIPPort inDstPort
)
505 MDNSInterfaceItem
* item
;
506 struct sockaddr_in addr
;
509 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
516 check( inInterfaceID
);
518 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
520 err
= mStatus_BadParamErr
;
525 // Make sure the InterfaceID is valid.
527 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
529 if( item
== (MDNSInterfaceItem
*) inInterfaceID
)
534 require_action( item
, exit
, err
= mStatus_NoSuchNameErr
);
539 item
= (MDNSInterfaceItem
*) inInterfaceID
;
540 check( item
->sendingSocketRef
!= kInvalidSocketRef
);
542 memset( &addr
, 0, sizeof( addr
) );
543 addr
.sin_family
= AF_INET
;
544 addr
.sin_port
= inDstPort
.NotAnInteger
;
545 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
547 n
= inMsgEnd
- ( (const mDNSu8
* const) inMsg
);
548 n
= sendto( item
->sendingSocketRef
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
549 check_errno( n
, errno
);
551 item
->sendErrorCounter
+= ( n
< 0 );
552 item
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
553 item
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
555 dlog( kDebugLevelChatty
, DEBUG_NAME
"sent (to=%u.%u.%u.%u:%hu)\n",
556 inDstIP
->ip
.v4
.b
[ 0 ], inDstIP
->ip
.v4
.b
[ 1 ], inDstIP
->ip
.v4
.b
[ 2 ], inDstIP
->ip
.v4
.b
[ 3 ],
557 htons( inDstPort
.NotAnInteger
) );
558 err
= mStatus_NoError
;
561 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
565 //===========================================================================================================================
566 // Connection-oriented (TCP) functions
567 //===========================================================================================================================
569 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
570 TCPConnectionCallback callback
, void *context
, int *descriptor
)
573 (void)dstport
; // Unused
574 (void)InterfaceID
; // Unused
575 (void)callback
; // Unused
576 (void)context
; // Unused
577 (void)descriptor
; // Unused
578 return(mStatus_UnsupportedErr
);
581 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
586 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
590 (void)buflen
; // Unused
594 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
602 //===========================================================================================================================
604 //===========================================================================================================================
606 void mDNSPlatformLock( const mDNS
* const inMDNS
)
608 check( inMDNS
->p
->lockID
);
610 if( inMDNS
->p
->lockID
)
612 #if( TARGET_NON_APPLE )
613 semTake( inMDNS
->p
->lockID
, WAIT_FOREVER
);
615 semTakeDeadlockDetect( inMDNS
->p
->lockID
, WAIT_FOREVER
);
620 //===========================================================================================================================
621 // mDNSPlatformUnlock
622 //===========================================================================================================================
624 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
628 check( inMDNS
->p
->lockID
);
629 check_string( inMDNS
->p
->task
!= ERROR
, "mDNS task not started" );
631 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
632 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
633 // (a) handle immediate work (if any) resulting from this API call
634 // (b) calculate the next sleep time between now and the next interesting event
636 if( ( mDNS_TimeNow(inMDNS
) - inMDNS
->NextScheduledEvent
) >= 0 )
638 // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
639 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
641 if( ( inMDNS
->p
->rescheduled
++ == 0 ) && ( taskIdSelf() != inMDNS
->p
->task
) )
643 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
647 if( inMDNS
->p
->lockID
)
649 semGive( inMDNS
->p
->lockID
);
653 //===========================================================================================================================
654 // mDNSPlatformStrLen
655 //===========================================================================================================================
657 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
661 return( (mDNSu32
) strlen( (const char *) inSrc
) );
664 //===========================================================================================================================
665 // mDNSPlatformStrCopy
666 //===========================================================================================================================
668 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
673 strcpy( (char *) inDst
, (const char*) inSrc
);
676 //===========================================================================================================================
677 // mDNSPlatformMemCopy
678 //===========================================================================================================================
680 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
685 memcpy( inDst
, inSrc
, inSize
);
688 //===========================================================================================================================
689 // mDNSPlatformMemSame
690 //===========================================================================================================================
692 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
697 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
700 //===========================================================================================================================
701 // mDNSPlatformMemZero
702 //===========================================================================================================================
704 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
708 memset( inDst
, 0, inSize
);
711 //===========================================================================================================================
712 // mDNSPlatformMemAllocate
713 //===========================================================================================================================
715 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
721 mem
= malloc( inSize
);
727 //===========================================================================================================================
728 // mDNSPlatformMemFree
729 //===========================================================================================================================
731 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
738 //===========================================================================================================================
739 // mDNSPlatformRandomSeed
740 //===========================================================================================================================
742 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
747 //===========================================================================================================================
748 // mDNSPlatformTimeInit
749 //===========================================================================================================================
751 mDNSexport mStatus
mDNSPlatformTimeInit( void )
753 // No special setup is required on VxWorks -- we just use tickGet().
754 return( mStatus_NoError
);
757 //===========================================================================================================================
758 // mDNSPlatformRawTime
759 //===========================================================================================================================
761 mDNSs32
mDNSPlatformRawTime( void )
763 return( (mDNSs32
) tickGet() );
766 //===========================================================================================================================
768 //===========================================================================================================================
770 mDNSexport mDNSs32
mDNSPlatformUTC( void )
775 //===========================================================================================================================
776 // mDNSPlatformInterfaceNameToID
777 //===========================================================================================================================
779 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
782 MDNSInterfaceItem
* ifd
;
788 // Search for an interface with the specified name,
790 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
792 if( strcmp( ifd
->name
, inName
) == 0 )
799 err
= mStatus_NoSuchNameErr
;
807 *outID
= (mDNSInterfaceID
) ifd
;
809 err
= mStatus_NoError
;
815 //===========================================================================================================================
816 // mDNSPlatformInterfaceIDToInfo
817 //===========================================================================================================================
819 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
822 MDNSInterfaceItem
* ifd
;
828 // Search for an interface with the specified ID,
830 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
832 if( ifd
== (MDNSInterfaceItem
*) inID
)
839 err
= mStatus_NoSuchNameErr
;
845 outInfo
->name
= ifd
->name
;
846 outInfo
->ip
= ifd
->hostSet
.ip
;
847 err
= mStatus_NoError
;
853 //===========================================================================================================================
855 //===========================================================================================================================
857 #if( MDNS_DEBUGMSGS )
858 mDNSexport
void debugf_( const char *format
, ... )
864 va_start( args
, format
);
865 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
868 dlog( kDebugLevelInfo
, "%s\n", buffer
);
872 //===========================================================================================================================
874 //===========================================================================================================================
876 #if( MDNS_DEBUGMSGS > 1 )
877 mDNSexport
void verbosedebugf_( const char *format
, ... )
883 va_start( args
, format
);
884 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
887 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
891 //===========================================================================================================================
893 //===========================================================================================================================
895 void LogMsg( const char *inFormat
, ... )
901 va_start( args
, inFormat
);
902 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
905 dlog( kDebugLevelWarning
, "%s\n", buffer
);
910 #pragma mark == Platform Internals ==
913 //===========================================================================================================================
915 //===========================================================================================================================
917 mDNSlocal
void SetupNames( mDNS
* const inMDNS
)
919 char tempCString
[ 128 ];
920 mDNSu8 tempPString
[ 128 ];
923 // Set up the host name.
925 tempCString
[ 0 ] = '\0';
926 GenerateUniqueHostName( tempCString
, NULL
);
927 check( tempCString
[ 0 ] != '\0' );
928 if( tempCString
[ 0 ] == '\0' )
930 // No name so use the default.
932 strcpy( tempCString
, kMDNSDefaultName
);
934 inMDNS
->nicelabel
.c
[ 0 ] = strlen( tempCString
);
935 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempCString
, inMDNS
->nicelabel
.c
[ 0 ] );
936 check( inMDNS
->nicelabel
.c
[ 0 ] > 0 );
938 // Set up the DNS name.
940 tempCString
[ 0 ] = '\0';
941 GenerateUniqueDNSName( tempCString
, NULL
);
942 if( tempCString
[ 0 ] != '\0' )
944 tempPString
[ 0 ] = strlen( tempCString
);
945 memcpy( &tempPString
[ 1 ], tempCString
, tempPString
[ 0 ] );
946 namePtr
= tempPString
;
950 // No DNS name so use the host name.
952 namePtr
= inMDNS
->nicelabel
.c
;
954 ConvertUTF8PstringToRFC1034HostLabel( namePtr
, &inMDNS
->hostlabel
);
955 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
957 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
959 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
961 check( inMDNS
->hostlabel
.c
[ 0 ] > 0 );
963 mDNS_SetFQDN( inMDNS
);
965 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
966 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
969 //===========================================================================================================================
970 // SetupInterfaceList
971 //===========================================================================================================================
973 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
976 struct ifaddrs
* addrs
;
980 MDNSInterfaceItem
** next
;
981 MDNSInterfaceItem
* item
;
985 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
988 // Tear down any existing interfaces that may be set up.
990 TearDownInterfaceList( inMDNS
);
991 inMDNS
->p
->interfaceList
= NULL
;
992 next
= &inMDNS
->p
->interfaceList
;
994 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
996 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTOPOINT
;
997 flagTest
= IFF_UP
| IFF_MULTICAST
;
999 err
= getifaddrs( &addrs
);
1000 require_noerr( err
, exit
);
1002 for( p
= addrs
; p
; p
= p
->ifa_next
)
1004 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
1006 err
= SetupInterface( inMDNS
, p
, &item
);
1007 require_noerr( err
, exit
);
1013 err
= mStatus_NoError
;
1018 freeifaddrs( addrs
);
1022 TearDownInterfaceList( inMDNS
);
1024 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
1028 //===========================================================================================================================
1029 // TearDownInterfaceList
1030 //===========================================================================================================================
1032 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1034 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
1037 // Tear down all the interfaces.
1039 while( inMDNS
->p
->interfaceList
)
1041 MDNSInterfaceItem
* item
;
1043 item
= inMDNS
->p
->interfaceList
;
1044 inMDNS
->p
->interfaceList
= item
->next
;
1046 TearDownInterface( inMDNS
, item
);
1049 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
1050 return( mStatus_NoError
);
1053 //===========================================================================================================================
1055 //===========================================================================================================================
1057 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
)
1060 MDNSInterfaceItem
* item
;
1061 MDNSSocketRef socketRef
;
1062 const struct sockaddr_in
* ipv4
, *mask
;
1064 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface (name=%s)\n", inAddr
->ifa_name
);
1067 check( inAddr
->ifa_addr
);
1068 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1069 mask
= (const struct sockaddr_in
*) inAddr
->ifa_netmask
;
1072 // Allocate memory for the info item.
1074 item
= (MDNSInterfaceItem
*) calloc( 1, sizeof( *item
) );
1075 require_action( item
, exit
, err
= mStatus_NoMemoryErr
);
1076 strcpy( item
->name
, inAddr
->ifa_name
);
1077 item
->multicastSocketRef
= kInvalidSocketRef
;
1078 item
->sendingSocketRef
= kInvalidSocketRef
;
1080 // Set up the multicast DNS (port 5353) socket for this interface.
1082 err
= SetupSocket( inMDNS
, inAddr
, MulticastDNSPort
, &socketRef
);
1083 require_noerr( err
, exit
);
1084 item
->multicastSocketRef
= socketRef
;
1086 // Set up the sending socket for this interface.
1088 err
= SetupSocket( inMDNS
, inAddr
, zeroIPPort
, &socketRef
);
1089 require_noerr( err
, exit
);
1090 item
->sendingSocketRef
= socketRef
;
1092 // Register this interface with mDNS.
1094 item
->hostSet
.InterfaceID
= (mDNSInterfaceID
) item
;
1095 item
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
1096 item
->hostSet
.ip
.ip
.v4
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1097 item
->hostSet
.mask
.type
= mDNSAddrType_IPv4
;
1098 item
->hostSet
.mask
.ip
.v4
.NotAnInteger
= mask
->sin_addr
.s_addr
;
1099 item
->hostSet
.ifname
[0] = 0;
1100 item
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1101 item
->hostSet
.McastTxRx
= mDNStrue
;
1103 err
= mDNS_RegisterInterface( inMDNS
, &item
->hostSet
);
1104 require_noerr( err
, exit
);
1105 item
->hostRegistered
= mDNStrue
;
1107 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1108 item
->hostSet
.ip
.ip
.v4
.b
[ 0 ], item
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1109 item
->hostSet
.ip
.ip
.v4
.b
[ 2 ], item
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1119 TearDownInterface( inMDNS
, item
);
1121 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (name=%s, err=%ld)\n", inAddr
->ifa_name
, err
);
1125 //===========================================================================================================================
1126 // TearDownInterface
1127 //===========================================================================================================================
1129 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
)
1131 MDNSSocketRef socketRef
;
1136 // Deregister this interface with mDNS.
1138 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1139 inItem
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1140 inItem
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1142 if( inItem
->hostRegistered
)
1144 inItem
->hostRegistered
= mDNSfalse
;
1145 mDNS_DeregisterInterface( inMDNS
, &inItem
->hostSet
);
1148 // Close the multicast socket.
1150 socketRef
= inItem
->multicastSocketRef
;
1151 inItem
->multicastSocketRef
= kInvalidSocketRef
;
1152 if( socketRef
!= kInvalidSocketRef
)
1154 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1158 // Close the sending socket.
1160 socketRef
= inItem
->sendingSocketRef
;
1161 inItem
->sendingSocketRef
= kInvalidSocketRef
;
1162 if( socketRef
!= kInvalidSocketRef
)
1164 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down sending socket %d\n", socketRef
);
1168 // Free the memory used by the interface info.
1171 return( mStatus_NoError
);
1174 //===========================================================================================================================
1176 //===========================================================================================================================
1180 mDNS
* const inMDNS
,
1181 const struct ifaddrs
* inAddr
,
1183 MDNSSocketRef
* outSocketRef
)
1186 MDNSSocketRef socketRef
;
1188 unsigned char optionByte
;
1189 struct ip_mreq mreq
;
1190 const struct sockaddr_in
* ipv4
;
1191 struct sockaddr_in addr
;
1194 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1197 check( inAddr
->ifa_addr
);
1198 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1199 check( outSocketRef
);
1201 // Set up a UDP socket for multicast DNS.
1203 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1204 require_errno_action( socketRef
, errno
, exit
, err
= mStatus_UnknownErr
);
1206 // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
1207 // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
1208 // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
1209 // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
1210 // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
1212 if( inPort
.NotAnInteger
!= zeroIPPort
.NotAnInteger
)
1214 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
1217 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1218 check_errno( err
, errno
);
1220 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1222 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1223 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1224 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1225 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1226 check_errno( err
, errno
);
1228 // Bind to the multicast DNS address and port 5353.
1230 memset( &addr
, 0, sizeof( addr
) );
1231 addr
.sin_family
= AF_INET
;
1232 addr
.sin_port
= inPort
.NotAnInteger
;
1233 addr
.sin_addr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1234 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1235 check_errno( err
, errno
);
1237 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
1238 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], ntohs( inPort
.NotAnInteger
), socketRef
);
1242 // Bind to the interface address and multicast DNS port.
1244 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1245 memset( &addr
, 0, sizeof( addr
) );
1246 addr
.sin_family
= AF_INET
;
1247 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1248 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1249 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1250 check_errno( err
, errno
);
1252 // Direct multicast packets to the specified interface.
1254 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1255 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1256 check_errno( err
, errno
);
1258 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1261 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1262 check_errno( err
, errno
);
1264 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1267 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &optionByte
, sizeof( optionByte
) );
1268 check_errno( err
, errno
);
1270 // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
1271 // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
1274 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
1276 option
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1277 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TOS
, (char *) &option
, sizeof( option
) );
1278 check_errno( err
, errno
);
1281 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
1282 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], socketRef
);
1287 *outSocketRef
= socketRef
;
1288 socketRef
= kInvalidSocketRef
;
1289 err
= mStatus_NoError
;
1292 if( socketRef
!= kInvalidSocketRef
)
1301 #pragma mark == Commands ==
1304 //===========================================================================================================================
1306 //===========================================================================================================================
1308 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1312 // Clean up any leftover command pipe.
1314 TearDownCommandPipe( inMDNS
);
1316 // Create the pipe device and open it.
1318 pipeDevCreate( kMDNSPipeName
, kMDNSPipeMessageQueueSize
, kMDNSPipeMessageSize
);
1320 inMDNS
->p
->commandPipe
= open( kMDNSPipeName
, O_RDWR
, 0 );
1321 require_errno_action( inMDNS
->p
->commandPipe
, errno
, exit
, err
= mStatus_UnsupportedErr
);
1323 err
= mStatus_NoError
;
1329 //===========================================================================================================================
1330 // TearDownCommandPipe
1331 //===========================================================================================================================
1333 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1335 if( inMDNS
->p
->commandPipe
!= ERROR
)
1337 close( inMDNS
->p
->commandPipe
);
1338 #ifdef _WRS_VXWORKS_5_X
1339 // pipeDevDelete is not defined in older versions of VxWorks
1340 pipeDevDelete( kMDNSPipeName
, FALSE
);
1342 inMDNS
->p
->commandPipe
= ERROR
;
1344 return( mStatus_NoError
);
1347 //===========================================================================================================================
1349 //===========================================================================================================================
1351 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1355 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1357 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1358 require_errno( err
, errno
, exit
);
1360 err
= mStatus_NoError
;
1366 //===========================================================================================================================
1368 //===========================================================================================================================
1370 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1373 MDNSPipeCommandCode commandCode
;
1375 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1377 // Read the command code from the pipe and dispatch it.
1379 err
= read( inMDNS
->p
->commandPipe
, &commandCode
, sizeof( commandCode
) );
1380 require_errno( err
, errno
, exit
);
1382 switch( commandCode
)
1384 case kMDNSPipeCommandCodeReschedule
:
1386 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
1388 dlog( kDebugLevelChatty
, DEBUG_NAME
"reschedule\n" );
1391 case kMDNSPipeCommandCodeReconfigure
:
1392 ProcessCommandReconfigure( inMDNS
);
1395 case kMDNSPipeCommandCodeQuit
:
1397 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
1399 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe quit command\n" );
1400 inMDNS
->p
->quit
= mDNStrue
;
1401 ++inMDNS
->p
->configID
;
1405 dlog( kDebugLevelError
, DEBUG_NAME
"unknown pipe command code (code=0x%08X)\n", commandCode
);
1406 err
= mStatus_BadParamErr
;
1410 err
= mStatus_NoError
;
1416 //===========================================================================================================================
1417 // ProcessCommandReconfigure
1418 //===========================================================================================================================
1420 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
)
1424 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe reconfigure command\n" );
1426 // Tear down the existing interfaces and set up new ones using the new IP info.
1428 mDNSPlatformLock( inMDNS
);
1430 err
= TearDownInterfaceList( inMDNS
);
1433 err
= SetupInterfaceList( inMDNS
);
1436 mDNSPlatformUnlock( inMDNS
);
1438 // Inform clients of the change.
1440 if( inMDNS
->MainCallback
)
1442 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1445 // Force mDNS to update.
1447 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
1449 // Bump the config ID so the main processing loop detects the configuration change.
1451 ++inMDNS
->p
->configID
;
1456 #pragma mark == Threads ==
1459 //===========================================================================================================================
1461 //===========================================================================================================================
1463 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
)
1468 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1471 // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
1472 // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
1473 // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
1475 task
= taskSpawn( kMDNSTaskName
, kMDNSTaskPriority
, 0, kMDNSTaskStackSize
, (FUNCPTR
) Task
,
1476 (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1477 require_action( task
!= ERROR
, exit
, err
= mStatus_NoMemoryErr
);
1479 err
= mStatus_NoError
;
1482 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld, id=%d)\n", err
, task
);
1486 //===========================================================================================================================
1488 //===========================================================================================================================
1490 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
)
1494 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread\n" );
1497 // Send a quit command to cause the thread to exit.
1499 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
1501 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
1503 if( inMDNS
->p
->quitEvent
)
1505 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
1508 err
= mStatus_NoError
;
1510 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread done (err=%ld)\n", err
);
1514 //===========================================================================================================================
1516 //===========================================================================================================================
1518 mDNSlocal
void Task( mDNS
*inMDNS
)
1522 MDNSInterfaceItem
* item
;
1525 struct timeval timeout
;
1527 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting\n" );
1530 // Set up everything up.
1532 err
= TaskInit( inMDNS
);
1533 require_noerr( err
, exit
);
1535 // Main Processing Loop.
1537 while( !inMDNS
->p
->quit
)
1539 // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
1540 // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
1542 TaskSetupReadSet( inMDNS
, &allReadSet
, &maxSocket
);
1543 configID
= inMDNS
->p
->configID
;
1544 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting processing loop (configID=%ld)\n", configID
);
1546 while( configID
== inMDNS
->p
->configID
)
1548 mDNSs32 nextTaskTime
;
1552 // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
1553 // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
1554 // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
1555 // processing packets. This introduces a window for a race condition because the thread wake-up and
1556 // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
1557 // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
1559 inMDNS
->p
->rescheduled
= 0;
1560 nextTaskTime
= mDNS_Execute( inMDNS
);
1561 TaskSetupTimeout( inMDNS
, nextTaskTime
, &timeout
);
1563 // Wait until something occurs (e.g. command, incoming packet, or timeout).
1565 readSet
= allReadSet
;
1566 n
= select( maxSocket
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1567 inMDNS
->p
->rescheduled
= 1;
1568 check_errno( n
, errno
);
1569 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"task select result = %d\n", n
);
1572 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1574 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS
) );
1578 // Scan the read set to determine if any sockets have something pending and process them.
1581 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1583 if( FD_ISSET( item
->multicastSocketRef
, &readSet
) )
1585 TaskProcessPacket( inMDNS
, item
, item
->multicastSocketRef
);
1590 // Check for a pending command and process it.
1592 if( FD_ISSET( inMDNS
->p
->commandPipe
, &readSet
) )
1594 ProcessCommand( inMDNS
);
1602 // Signal we've quit.
1604 check( inMDNS
->p
->quitEvent
);
1605 semGive( inMDNS
->p
->quitEvent
);
1607 dlog( kDebugLevelInfo
, DEBUG_NAME
"task ended\n" );
1610 //===========================================================================================================================
1612 //===========================================================================================================================
1614 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1618 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init\n" );
1619 check( inMDNS
->p
->readyEvent
);
1621 inMDNS
->p
->task
= taskIdSelf();
1623 err
= SetupCommandPipe( inMDNS
);
1624 require_noerr( err
, exit
);
1626 SetupNames( inMDNS
);
1628 err
= SetupInterfaceList( inMDNS
);
1629 require_noerr( err
, exit
);
1632 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1634 inMDNS
->p
->taskInitErr
= err
;
1635 semGive( inMDNS
->p
->readyEvent
);
1637 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init done (err=%ld)\n", err
);
1641 //===========================================================================================================================
1643 //===========================================================================================================================
1645 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
)
1647 MDNSInterfaceItem
* item
;
1650 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set\n" );
1652 check( outReadSet
);
1653 check( outMaxSocket
);
1655 // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
1656 // should never happen since we should always have at least one interface, but it's just to be safe.
1658 FD_ZERO( outReadSet
);
1661 // Add all the receiving sockets to the read set.
1663 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1665 FD_SET( item
->multicastSocketRef
, outReadSet
);
1666 if( item
->multicastSocketRef
> maxSocket
)
1668 maxSocket
= item
->multicastSocketRef
;
1672 // Add the command pipe to the read set.
1674 FD_SET( inMDNS
->p
->commandPipe
, outReadSet
);
1675 if( inMDNS
->p
->commandPipe
> maxSocket
)
1677 maxSocket
= inMDNS
->p
->commandPipe
;
1679 check( maxSocket
> 0 );
1680 *outMaxSocket
= maxSocket
;
1682 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set done (maxSocket=%d)\n", maxSocket
);
1685 //===========================================================================================================================
1687 //===========================================================================================================================
1689 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
)
1693 // Calculate how long to wait before performing idle processing.
1695 delta
= inNextTaskTime
- mDNS_TimeNow(inMDNS
);
1698 // The next task time is now or in the past. Set the timeout to fire immediately.
1700 outTimeout
->tv_sec
= 0;
1701 outTimeout
->tv_usec
= 0;
1705 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1706 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1708 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1709 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicrosecondsMultiplier
;
1711 // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
1713 if( outTimeout
->tv_usec
>= 1000000L )
1715 outTimeout
->tv_sec
+= 1;
1716 outTimeout
->tv_usec
= 0;
1720 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task in %ld:%ld seconds (%ld)\n",
1721 outTimeout
->tv_sec
, outTimeout
->tv_usec
, inNextTaskTime
);
1723 //===========================================================================================================================
1724 // TaskProcessPacket
1725 //===========================================================================================================================
1727 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
)
1731 struct sockaddr_in addr
;
1733 mDNSu8
* packetEndPtr
;
1739 // Receive the packet.
1741 addrSize
= sizeof( addr
);
1742 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1746 // Set up the src/dst/interface info.
1748 srcAddr
.type
= mDNSAddrType_IPv4
;
1749 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1750 srcPort
.NotAnInteger
= addr
.sin_port
;
1751 dstAddr
.type
= mDNSAddrType_IPv4
;
1752 dstAddr
.ip
.v4
= AllDNSLinkGroupv4
;
1753 dstPort
= MulticastDNSPort
;
1755 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1756 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1757 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%hu\n",
1758 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1759 ntohs( srcPort
.NotAnInteger
) );
1760 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%hu\n",
1761 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1762 ntohs( dstPort
.NotAnInteger
) );
1763 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = 0x%08X\n", (int) inItem
->hostSet
.InterfaceID
);
1764 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1766 // Dispatch the packet to mDNS.
1768 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1769 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inItem
->hostSet
.InterfaceID
);
1774 inItem
->recvCounter
+= 1;
1775 inItem
->recvErrorCounter
+= ( n
< 0 );
1780 #pragma mark == Utilities ==
1783 #if( TARGET_NON_APPLE )
1784 //===========================================================================================================================
1785 // GenerateUniqueHostName
1787 // Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
1788 //===========================================================================================================================
1790 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
)
1792 DEBUG_UNUSED( ioSeed
);
1794 // $$$ Non-Apple Platforms: Fill in appropriate name for device.
1796 mDNSPlatformStrCopy( kMDNSDefaultName
, outName
);
1799 //===========================================================================================================================
1800 // GenerateUniqueDNSName
1802 // Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
1803 // implemented to return a unique name.
1804 //===========================================================================================================================
1806 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
)
1808 DEBUG_UNUSED( ioSeed
);
1810 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
1812 mDNSPlatformStrCopy( kMDNSDefaultName
, outName
);
1820 //===========================================================================================================================
1822 //===========================================================================================================================
1824 int getifaddrs( struct ifaddrs
**outAddrs
)
1827 struct ifaddrs
* head
;
1828 struct ifaddrs
** next
;
1829 struct ifaddrs
* ifa
;
1832 char ipString
[ INET_ADDR_LEN
];
1841 ifp
= ifIndexToIfp( i
);
1848 // Allocate and initialize the ifaddrs structure and attach it to the linked list.
1850 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1851 require_action( ifa
, exit
, err
= ENOMEM
);
1854 next
= &ifa
->ifa_next
;
1858 ifa
->ifa_name
= (char *) malloc( 16 );
1859 require_action( ifa
->ifa_name
, exit
, err
= ENOMEM
);
1861 n
= sprintf( ifa
->ifa_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
1862 require_action( n
< 16, exit
, err
= ENOBUFS
);
1864 // Fetch the address.
1866 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( struct sockaddr_in
) );
1867 require_action( ifa
->ifa_addr
, exit
, err
= ENOMEM
);
1869 ipString
[ 0 ] = '\0';
1870 #if( TARGET_NON_APPLE )
1871 err
= ifAddrGet( ifa
->ifa_name
, ipString
);
1872 require_noerr( err
, exit
);
1874 err
= ifAddrGetNonAlias( ifa
->ifa_name
, ipString
);
1875 require_noerr( err
, exit
);
1878 err
= sock_pton( ipString
, AF_INET
, ifa
->ifa_addr
, 0, NULL
);
1879 require_noerr( err
, exit
);
1883 ifa
->ifa_flags
= ifp
->if_flags
;
1898 freeifaddrs( head
);
1903 //===========================================================================================================================
1905 //===========================================================================================================================
1907 void freeifaddrs( struct ifaddrs
*inAddrs
)
1912 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
1914 for( p
= inAddrs
; p
; p
= q
)
1920 free( p
->ifa_name
);
1925 free( p
->ifa_addr
);
1928 if( p
->ifa_netmask
)
1930 free( p
->ifa_netmask
);
1931 p
->ifa_netmask
= NULL
;
1933 if( p
->ifa_dstaddr
)
1935 free( p
->ifa_dstaddr
);
1936 p
->ifa_dstaddr
= NULL
;
1940 free( p
->ifa_data
);
1947 //===========================================================================================================================
1949 //===========================================================================================================================
1951 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
1955 if( inFamily
== AF_INET
)
1957 struct sockaddr_in
* ipv4
;
1959 if( inAddrSize
== 0 )
1961 inAddrSize
= sizeof( struct sockaddr_in
);
1963 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1969 ipv4
= (struct sockaddr_in
*) outAddr
;
1970 err
= inet_aton( (char *) inString
, &ipv4
->sin_addr
);
1973 ipv4
->sin_family
= AF_INET
;
1976 *outAddrSize
= sizeof( struct sockaddr_in
);
1980 #if( defined( AF_INET6 ) )
1981 else if( inFamily
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
1997 //===========================================================================================================================
1999 //===========================================================================================================================
2001 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
2003 const struct sockaddr
* addr
;
2005 addr
= (const struct sockaddr
*) inAddr
;
2006 if( addr
->sa_family
== AF_INET
)
2008 struct sockaddr_in
* ipv4
;
2010 if( inAddrSize
== 0 )
2012 inAddrSize
= sizeof( struct sockaddr_in
);
2014 if( inAddrSize
< sizeof( struct sockaddr_in
) )
2020 if( inBufferSize
< 16 )
2027 ipv4
= (struct sockaddr_in
*) addr
;
2028 inet_ntoa_b( ipv4
->sin_addr
, inBuffer
);
2030 #if( defined( AF_INET6 ) )
2031 else if( addr
->sa_family
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2033 errno
= EAFNOSUPPORT
;
2040 errno
= EAFNOSUPPORT
;
2051 #pragma mark == Debugging ==
2056 void mDNSShow( BOOL inShowRecords
);
2057 void mDNSShowRecords( void );
2058 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
);
2060 //===========================================================================================================================
2062 //===========================================================================================================================
2064 void mDNSShow( BOOL inShowRecords
)
2066 MDNSInterfaceItem
* item
;
2072 printf( "### mDNS not initialized\n" );
2078 printf( "\n-- mDNS globals --\n" );
2079 printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2080 printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2081 printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2082 printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2083 printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr
);
2084 printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier
);
2085 printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->lockID
);
2086 printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->readyEvent
);
2087 printf( " taskInitErr = %ld\n", gMDNSPtr
->p
->taskInitErr
);
2088 printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->quitEvent
);
2089 printf( " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2090 printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->task
);
2091 printf( " quit = %d\n", gMDNSPtr
->p
->quit
);
2092 printf( " configID = %ld\n", gMDNSPtr
->p
->configID
);
2093 printf( " rescheduled = %d\n", gMDNSPtr
->p
->rescheduled
);
2094 printf( " nicelabel = \"%.*s\"\n", gMDNSPtr
->nicelabel
.c
[ 0 ], (char *) &gMDNSPtr
->nicelabel
.c
[ 1 ] );
2095 printf( " hostLabel = \"%.*s\"\n", gMDNSPtr
->hostlabel
.c
[ 0 ], (char *) &gMDNSPtr
->hostlabel
.c
[ 1 ] );
2100 printf( "\n-- mDNS interfaces --\n" );
2102 for( item
= gMDNSPtr
->p
->interfaceList
; item
; item
= item
->next
)
2104 printf( " -- interface %u --\n", n
);
2105 printf( " name = \"%s\"\n", item
->name
);
2106 printf( " multicastSocketRef = %d\n", item
->multicastSocketRef
);
2107 printf( " sendingSocketRef = %d\n", item
->sendingSocketRef
);
2108 ip
= item
->hostSet
.ip
;
2109 printf( " hostSet.ip = %u.%u.%u.%u\n", ip
.ip
.v4
.b
[ 0 ], ip
.ip
.v4
.b
[ 1 ],
2110 ip
.ip
.v4
.b
[ 2 ], ip
.ip
.v4
.b
[ 3 ] );
2111 printf( " hostSet.advertise = %s\n", item
->hostSet
.Advertise
? "YES" : "NO" );
2112 printf( " hostRegistered = %s\n", item
->hostRegistered
? "YES" : "NO" );
2114 printf( " sendMulticastCounter = %d\n", item
->sendMulticastCounter
);
2115 printf( " sendUnicastCounter = %d\n", item
->sendUnicastCounter
);
2116 printf( " sendErrorCounter = %d\n", item
->sendErrorCounter
);
2117 printf( " recvCounter = %d\n", item
->recvCounter
);
2118 printf( " recvErrorCounter = %d\n", item
->recvErrorCounter
);
2119 printf( " recvLoopCounter = %d\n", item
->recvLoopCounter
);
2132 //===========================================================================================================================
2134 //===========================================================================================================================
2136 void mDNSShowRecords( void )
2138 MDNSInterfaceItem
* item
;
2140 AuthRecord
* record
;
2141 char name
[ MAX_ESCAPED_DOMAIN_NAME
];
2143 printf( "\n-- mDNS resource records --\n" );
2145 for( record
= gMDNSPtr
->ResourceRecords
; record
; record
= record
->next
)
2147 item
= (MDNSInterfaceItem
*) record
->resrec
.InterfaceID
;
2148 ConvertDomainNameToCString( &record
->resrec
.name
, name
);
2149 printf( " -- record %d --\n", n
);
2150 printf( " interface = 0x%08X (%s)\n", (int) item
, item
? item
->name
: "<any>" );
2151 printf( " name = \"%s\"\n", name
);
2158 //===========================================================================================================================
2160 //===========================================================================================================================
2162 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
)
2169 printf( "\nTXT record (%u bytes):\n\n", inTXTSize
);
2171 p
= (const mDNSu8
*) inTXT
;
2172 end
= p
+ inTXTSize
;
2178 if( ( p
+ size
) > end
)
2180 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
2183 printf( "%2d (%3d bytes): \"%.*s\"\n", i
, size
, size
, p
);