1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Contains: mDNS platform plugin for VxWorks.
19 Copyright: Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
21 Change History (most recent first):
23 $Log: mDNSVxWorksIPv4Only.c,v $
24 Revision 1.31 2007/03/22 18:31:49 cheshire
25 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
27 Revision 1.30 2006/12/19 22:43:56 cheshire
30 Revision 1.29 2006/08/14 23:25:18 cheshire
31 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
33 Revision 1.28 2006/03/19 02:00:12 cheshire
34 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
36 Revision 1.27 2004/12/17 23:37:49 cheshire
37 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
38 (and other repetitive configuration changes)
40 Revision 1.26 2004/10/28 02:00:35 cheshire
41 <rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
43 Revision 1.25 2004/10/16 00:17:01 cheshire
44 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
46 Revision 1.24 2004/09/21 21:02:56 cheshire
47 Set up ifname before calling mDNS_RegisterInterface()
49 Revision 1.23 2004/09/17 01:08:57 cheshire
50 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
51 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
52 declared in that file are ONLY appropriate to single-address-space embedded applications.
53 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
55 Revision 1.22 2004/09/17 00:19:11 cheshire
56 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
58 Revision 1.21 2004/09/16 00:24:50 cheshire
59 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
61 Revision 1.20 2004/09/14 23:42:36 cheshire
62 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
64 Revision 1.19 2004/09/14 23:16:09 cheshire
65 mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
67 Revision 1.18 2004/08/14 03:22:42 cheshire
68 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
69 Add GetUserSpecifiedDDNSName() routine
70 Convert ServiceRegDomain to domainname instead of C string
71 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
73 Revision 1.17 2004/07/29 19:26:03 ksekar
74 Plaform-level changes for NAT-PMP support
76 Revision 1.16 2004/04/22 05:11:28 bradley
77 Added mDNSPlatformUTC for TSIG signed dynamic updates.
79 Revision 1.15 2004/04/21 02:49:12 cheshire
80 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
82 Revision 1.14 2004/04/09 17:43:04 cheshire
83 Make sure to set the McastTxRx field so that duplicate suppression works correctly
85 Revision 1.13 2004/01/27 20:15:24 cheshire
86 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
88 Revision 1.12 2004/01/24 09:12:37 bradley
89 Avoid TOS socket options to workaround a TOS routing problem with VxWorks and multiple interfaces
90 when sending unicast responses, which resulted in packets going out the wrong interface.
92 Revision 1.11 2004/01/24 04:59:16 cheshire
93 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
95 Revision 1.10 2003/11/14 21:27:09 cheshire
96 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
97 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
99 Revision 1.9 2003/11/14 20:59:09 cheshire
100 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
101 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
103 Revision 1.8 2003/10/28 10:08:27 bradley
104 Removed legacy port 53 support as it is no longer needed.
106 Revision 1.7 2003/08/20 05:58:54 bradley
107 Removed dependence on modified mDNSCore: define structures/prototypes locally.
109 Revision 1.6 2003/08/18 23:19:05 cheshire
110 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
112 Revision 1.5 2003/08/15 00:05:04 bradley
113 Updated to use name/InterfaceID from new AuthRecord resrec field. Added output of new record sizes.
115 Revision 1.4 2003/08/14 02:19:55 cheshire
116 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
118 Revision 1.3 2003/08/12 19:56:27 cheshire
121 Revision 1.2 2003/08/05 23:58:34 cheshire
122 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
123 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
125 Revision 1.1 2003/08/02 10:06:48 bradley
126 mDNS platform plugin for VxWorks.
129 Notes for non-Apple platforms:
131 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
135 - Add support for IPv6 (needs VxWorks IPv6 support).
138 // Set up the debug library to use the default category (see DebugServicesLite.h for details).
140 #if( !TARGET_NON_APPLE )
141 #define DEBUG_USE_DEFAULT_CATEGORY 1
150 #include <sys/types.h>
151 #include <arpa/inet.h>
153 #include <netinet/if_ether.h>
154 #include <netinet/in.h>
155 #include <netinet/ip.h>
156 #include <sys/ioctl.h>
157 #include <sys/socket.h>
164 #include "selectLib.h"
173 #if( !TARGET_NON_APPLE )
174 #include "ACP/ACPUtilities.h"
175 #include "Support/DebugServicesLite.h"
176 #include "Support/MiscUtilities.h"
179 #include "mDNSEmbeddedAPI.h"
181 #include "mDNSVxWorks.h"
184 #pragma mark == Preprocessor ==
187 //===========================================================================================================================
189 //===========================================================================================================================
191 #if( !TARGET_NON_APPLE )
192 debug_log_new_default_category( mdns
);
196 #pragma mark == Constants ==
199 //===========================================================================================================================
201 //===========================================================================================================================
203 #define DEBUG_NAME "[mDNS] "
205 #define kMDNSDefaultName "My-Device"
207 #define kMDNSTaskName "tMDNS"
208 #define kMDNSTaskPriority 102
209 #define kMDNSTaskStackSize 49152
211 #define kMDNSPipeName "/pipe/mDNS"
212 #define kMDNSPipeMessageQueueSize 32
213 #define kMDNSPipeMessageSize 1
215 #define kInvalidSocketRef -1
217 typedef uint8_t MDNSPipeCommandCode
;
220 kMDNSPipeCommandCodeInvalid
= 0,
221 kMDNSPipeCommandCodeReschedule
= 1,
222 kMDNSPipeCommandCodeReconfigure
= 2,
223 kMDNSPipeCommandCodeQuit
= 3
227 #pragma mark == Structures ==
230 //===========================================================================================================================
232 //===========================================================================================================================
234 typedef int MDNSSocketRef
;
236 struct MDNSInterfaceItem
238 MDNSInterfaceItem
* next
;
240 MDNSSocketRef multicastSocketRef
;
241 MDNSSocketRef sendingSocketRef
;
242 NetworkInterfaceInfo hostSet
;
243 mDNSBool hostRegistered
;
245 int sendMulticastCounter
;
246 int sendUnicastCounter
;
247 int sendErrorCounter
;
250 int recvErrorCounter
;
255 #pragma mark == Macros ==
258 //===========================================================================================================================
260 //===========================================================================================================================
262 #if( TARGET_NON_APPLE )
264 // Do-nothing versions of the debugging macros for non-Apple platforms.
266 #define check(assertion)
267 #define check_string( assertion, cstring )
268 #define check_noerr(err)
269 #define check_noerr_string( error, cstring )
270 #define check_errno( assertion, errno_value )
271 #define debug_string( cstring )
272 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
273 #define require_string( assertion, label, string ) require(assertion, label)
274 #define require_quiet( assertion, label ) require( assertion, label )
275 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
276 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
277 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
278 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
279 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
280 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
281 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
282 #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label; } while(0)
283 #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
285 #define dlog( ARGS... )
287 #define DEBUG_UNUSED( X ) (void)( X )
291 #pragma mark == Prototypes ==
294 //===========================================================================================================================
296 //===========================================================================================================================
298 // ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
300 extern struct ifnet
* ifIndexToIfp(int ifIndex
);
302 // Platform Internals
304 mDNSlocal
void SetupNames( mDNS
* const inMDNS
);
305 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
306 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
307 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
);
308 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
);
312 const struct ifaddrs
* inAddr
,
314 MDNSSocketRef
* outSocketRef
);
318 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
319 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
320 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
321 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
322 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
);
326 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
);
327 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
);
328 mDNSlocal
void Task( mDNS
*inMDNS
);
329 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
330 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
);
331 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
);
332 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
);
336 #if( TARGET_NON_APPLE )
337 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
);
338 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
);
341 // Platform Accessors
347 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
348 struct mDNSPlatformInterfaceInfo
354 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
355 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
362 #pragma mark == Globals ==
365 //===========================================================================================================================
367 //===========================================================================================================================
369 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
370 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
371 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier
= 0;
375 mDNSs32 mDNSPlatformOneSecond
;
379 #pragma mark == Public APIs ==
382 //===========================================================================================================================
384 //===========================================================================================================================
386 void mDNSReconfigure( void )
388 // Send a "reconfigure" command to the MDNS task.
392 SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
398 #pragma mark == Platform Support ==
401 //===========================================================================================================================
403 //===========================================================================================================================
405 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
409 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init\n" );
411 // Initialize variables.
413 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
414 inMDNS
->p
= &gMDNSPlatformSupport
;
415 inMDNS
->p
->commandPipe
= ERROR
;
416 inMDNS
->p
->task
= ERROR
;
417 inMDNS
->p
->rescheduled
= 1; // Default to rescheduled until fully initialized.
418 mDNSPlatformOneSecond
= sysClkRateGet();
419 gMDNSTicksToMicrosecondsMultiplier
= ( 1000000L / mDNSPlatformOneSecond
);
421 // Allocate semaphores.
423 inMDNS
->p
->lockID
= semMCreate( SEM_Q_FIFO
);
424 require_action( inMDNS
->p
->lockID
, exit
, err
= mStatus_NoMemoryErr
);
426 inMDNS
->p
->readyEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
427 require_action( inMDNS
->p
->readyEvent
, exit
, err
= mStatus_NoMemoryErr
);
429 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
430 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
434 // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
435 // stack space issues. Some of the initialization may require a larger stack than the current task supports.
437 err
= SetupTask( inMDNS
);
438 require_noerr( err
, exit
);
440 err
= semTake( inMDNS
->p
->readyEvent
, WAIT_FOREVER
);
441 require_noerr( err
, exit
);
442 err
= inMDNS
->p
->taskInitErr
;
443 require_noerr( err
, exit
);
445 mDNSCoreInitComplete( inMDNS
, err
);
450 mDNSPlatformClose( inMDNS
);
452 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
456 //===========================================================================================================================
458 //===========================================================================================================================
460 void mDNSPlatformClose( mDNS
* const inMDNS
)
464 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close\n" );
467 // Tear everything down.
469 err
= TearDownTask( inMDNS
);
472 err
= TearDownInterfaceList( inMDNS
);
475 err
= TearDownCommandPipe( inMDNS
);
480 // Release semaphores.
482 if( inMDNS
->p
->quitEvent
)
484 semDelete( inMDNS
->p
->quitEvent
);
485 inMDNS
->p
->quitEvent
= 0;
487 if( inMDNS
->p
->readyEvent
)
489 semDelete( inMDNS
->p
->readyEvent
);
490 inMDNS
->p
->readyEvent
= 0;
492 if( inMDNS
->p
->lockID
)
494 semDelete( inMDNS
->p
->lockID
);
495 inMDNS
->p
->lockID
= 0;
498 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close done\n" );
501 //===========================================================================================================================
502 // mDNSPlatformSendUDP
503 //===========================================================================================================================
507 const mDNS
* const inMDNS
,
508 const void * const inMsg
,
509 const mDNSu8
* const inMsgEnd
,
510 mDNSInterfaceID inInterfaceID
,
511 const mDNSAddr
* inDstIP
,
512 mDNSIPPort inDstPort
)
515 MDNSInterfaceItem
* item
;
516 struct sockaddr_in addr
;
519 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
526 check( inInterfaceID
);
528 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
530 err
= mStatus_BadParamErr
;
535 // Make sure the InterfaceID is valid.
537 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
539 if( item
== (MDNSInterfaceItem
*) inInterfaceID
)
544 require_action( item
, exit
, err
= mStatus_NoSuchNameErr
);
549 item
= (MDNSInterfaceItem
*) inInterfaceID
;
550 check( item
->sendingSocketRef
!= kInvalidSocketRef
);
552 memset( &addr
, 0, sizeof( addr
) );
553 addr
.sin_family
= AF_INET
;
554 addr
.sin_port
= inDstPort
.NotAnInteger
;
555 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
557 n
= inMsgEnd
- ( (const mDNSu8
* const) inMsg
);
558 n
= sendto( item
->sendingSocketRef
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
559 check_errno( n
, errno
);
561 item
->sendErrorCounter
+= ( n
< 0 );
562 item
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
563 item
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
565 dlog( kDebugLevelChatty
, DEBUG_NAME
"sent (to=%u.%u.%u.%u:%hu)\n",
566 inDstIP
->ip
.v4
.b
[ 0 ], inDstIP
->ip
.v4
.b
[ 1 ], inDstIP
->ip
.v4
.b
[ 2 ], inDstIP
->ip
.v4
.b
[ 3 ],
567 htons( inDstPort
.NotAnInteger
) );
568 err
= mStatus_NoError
;
571 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
575 //===========================================================================================================================
576 // Connection-oriented (TCP) functions
577 //===========================================================================================================================
579 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
580 TCPConnectionCallback callback
, void *context
, int *descriptor
)
583 (void)dstport
; // Unused
584 (void)InterfaceID
; // Unused
585 (void)callback
; // Unused
586 (void)context
; // Unused
587 (void)descriptor
; // Unused
588 return(mStatus_UnsupportedErr
);
591 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
596 mDNSexport
long mDNSPlatformReadTCP(int sd
, void *buf
, unsigned long buflen
)
600 (void)buflen
; // Unused
604 mDNSexport
long mDNSPlatformWriteTCP(int sd
, const char *msg
, unsigned long len
)
612 //===========================================================================================================================
614 //===========================================================================================================================
616 void mDNSPlatformLock( const mDNS
* const inMDNS
)
618 check( inMDNS
->p
->lockID
);
620 if( inMDNS
->p
->lockID
)
622 #if( TARGET_NON_APPLE )
623 semTake( inMDNS
->p
->lockID
, WAIT_FOREVER
);
625 semTakeDeadlockDetect( inMDNS
->p
->lockID
, WAIT_FOREVER
);
630 //===========================================================================================================================
631 // mDNSPlatformUnlock
632 //===========================================================================================================================
634 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
638 check( inMDNS
->p
->lockID
);
639 check_string( inMDNS
->p
->task
!= ERROR
, "mDNS task not started" );
641 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
642 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
643 // (a) handle immediate work (if any) resulting from this API call
644 // (b) calculate the next sleep time between now and the next interesting event
646 if( ( mDNS_TimeNow(inMDNS
) - inMDNS
->NextScheduledEvent
) >= 0 )
648 // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
649 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
651 if( ( inMDNS
->p
->rescheduled
++ == 0 ) && ( taskIdSelf() != inMDNS
->p
->task
) )
653 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
657 if( inMDNS
->p
->lockID
)
659 semGive( inMDNS
->p
->lockID
);
663 //===========================================================================================================================
664 // mDNSPlatformStrLen
665 //===========================================================================================================================
667 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
671 return( (mDNSu32
) strlen( (const char *) inSrc
) );
674 //===========================================================================================================================
675 // mDNSPlatformStrCopy
676 //===========================================================================================================================
678 void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
683 strcpy( (char *) inDst
, (const char*) inSrc
);
686 //===========================================================================================================================
687 // mDNSPlatformMemCopy
688 //===========================================================================================================================
690 void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
695 memcpy( inDst
, inSrc
, inSize
);
698 //===========================================================================================================================
699 // mDNSPlatformMemSame
700 //===========================================================================================================================
702 mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
707 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
710 //===========================================================================================================================
711 // mDNSPlatformMemZero
712 //===========================================================================================================================
714 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
718 memset( inDst
, 0, inSize
);
721 //===========================================================================================================================
722 // mDNSPlatformMemAllocate
723 //===========================================================================================================================
725 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
731 mem
= malloc( inSize
);
737 //===========================================================================================================================
738 // mDNSPlatformMemFree
739 //===========================================================================================================================
741 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
748 //===========================================================================================================================
749 // mDNSPlatformRandomSeed
750 //===========================================================================================================================
752 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
757 //===========================================================================================================================
758 // mDNSPlatformTimeInit
759 //===========================================================================================================================
761 mDNSexport mStatus
mDNSPlatformTimeInit( void )
763 // No special setup is required on VxWorks -- we just use tickGet().
764 return( mStatus_NoError
);
767 //===========================================================================================================================
768 // mDNSPlatformRawTime
769 //===========================================================================================================================
771 mDNSs32
mDNSPlatformRawTime( void )
773 return( (mDNSs32
) tickGet() );
776 //===========================================================================================================================
778 //===========================================================================================================================
780 mDNSexport mDNSs32
mDNSPlatformUTC( void )
785 //===========================================================================================================================
786 // mDNSPlatformInterfaceNameToID
787 //===========================================================================================================================
789 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
792 MDNSInterfaceItem
* ifd
;
798 // Search for an interface with the specified name,
800 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
802 if( strcmp( ifd
->name
, inName
) == 0 )
809 err
= mStatus_NoSuchNameErr
;
817 *outID
= (mDNSInterfaceID
) ifd
;
819 err
= mStatus_NoError
;
825 //===========================================================================================================================
826 // mDNSPlatformInterfaceIDToInfo
827 //===========================================================================================================================
829 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
832 MDNSInterfaceItem
* ifd
;
838 // Search for an interface with the specified ID,
840 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
842 if( ifd
== (MDNSInterfaceItem
*) inID
)
849 err
= mStatus_NoSuchNameErr
;
855 outInfo
->name
= ifd
->name
;
856 outInfo
->ip
= ifd
->hostSet
.ip
;
857 err
= mStatus_NoError
;
863 //===========================================================================================================================
865 //===========================================================================================================================
867 #if( MDNS_DEBUGMSGS )
868 mDNSexport
void debugf_( const char *format
, ... )
874 va_start( args
, format
);
875 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
878 dlog( kDebugLevelInfo
, "%s\n", buffer
);
882 //===========================================================================================================================
884 //===========================================================================================================================
886 #if( MDNS_DEBUGMSGS > 1 )
887 mDNSexport
void verbosedebugf_( const char *format
, ... )
893 va_start( args
, format
);
894 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
897 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
901 //===========================================================================================================================
903 //===========================================================================================================================
905 void LogMsg( const char *inFormat
, ... )
911 va_start( args
, inFormat
);
912 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
915 dlog( kDebugLevelWarning
, "%s\n", buffer
);
920 #pragma mark == Platform Internals ==
923 //===========================================================================================================================
925 //===========================================================================================================================
927 mDNSlocal
void SetupNames( mDNS
* const inMDNS
)
929 char tempCString
[ 128 ];
930 mDNSu8 tempPString
[ 128 ];
933 // Set up the host name.
935 tempCString
[ 0 ] = '\0';
936 GenerateUniqueHostName( tempCString
, NULL
);
937 check( tempCString
[ 0 ] != '\0' );
938 if( tempCString
[ 0 ] == '\0' )
940 // No name so use the default.
942 strcpy( tempCString
, kMDNSDefaultName
);
944 inMDNS
->nicelabel
.c
[ 0 ] = strlen( tempCString
);
945 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempCString
, inMDNS
->nicelabel
.c
[ 0 ] );
946 check( inMDNS
->nicelabel
.c
[ 0 ] > 0 );
948 // Set up the DNS name.
950 tempCString
[ 0 ] = '\0';
951 GenerateUniqueDNSName( tempCString
, NULL
);
952 if( tempCString
[ 0 ] != '\0' )
954 tempPString
[ 0 ] = strlen( tempCString
);
955 memcpy( &tempPString
[ 1 ], tempCString
, tempPString
[ 0 ] );
956 namePtr
= tempPString
;
960 // No DNS name so use the host name.
962 namePtr
= inMDNS
->nicelabel
.c
;
964 ConvertUTF8PstringToRFC1034HostLabel( namePtr
, &inMDNS
->hostlabel
);
965 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
967 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
969 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
971 check( inMDNS
->hostlabel
.c
[ 0 ] > 0 );
973 mDNS_SetFQDN( inMDNS
);
975 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
976 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
979 //===========================================================================================================================
980 // SetupInterfaceList
981 //===========================================================================================================================
983 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
986 struct ifaddrs
* addrs
;
990 MDNSInterfaceItem
** next
;
991 MDNSInterfaceItem
* item
;
995 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
998 // Tear down any existing interfaces that may be set up.
1000 TearDownInterfaceList( inMDNS
);
1001 inMDNS
->p
->interfaceList
= NULL
;
1002 next
= &inMDNS
->p
->interfaceList
;
1004 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
1006 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTOPOINT
;
1007 flagTest
= IFF_UP
| IFF_MULTICAST
;
1009 err
= getifaddrs( &addrs
);
1010 require_noerr( err
, exit
);
1012 for( p
= addrs
; p
; p
= p
->ifa_next
)
1014 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
1016 err
= SetupInterface( inMDNS
, p
, &item
);
1017 require_noerr( err
, exit
);
1023 err
= mStatus_NoError
;
1028 freeifaddrs( addrs
);
1032 TearDownInterfaceList( inMDNS
);
1034 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
1038 //===========================================================================================================================
1039 // TearDownInterfaceList
1040 //===========================================================================================================================
1042 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1044 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
1047 // Tear down all the interfaces.
1049 while( inMDNS
->p
->interfaceList
)
1051 MDNSInterfaceItem
* item
;
1053 item
= inMDNS
->p
->interfaceList
;
1054 inMDNS
->p
->interfaceList
= item
->next
;
1056 TearDownInterface( inMDNS
, item
);
1059 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
1060 return( mStatus_NoError
);
1063 //===========================================================================================================================
1065 //===========================================================================================================================
1067 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
)
1070 MDNSInterfaceItem
* item
;
1071 MDNSSocketRef socketRef
;
1072 const struct sockaddr_in
* ipv4
, *mask
;
1074 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface (name=%s)\n", inAddr
->ifa_name
);
1077 check( inAddr
->ifa_addr
);
1078 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1079 mask
= (const struct sockaddr_in
*) inAddr
->ifa_netmask
;
1082 // Allocate memory for the info item.
1084 item
= (MDNSInterfaceItem
*) calloc( 1, sizeof( *item
) );
1085 require_action( item
, exit
, err
= mStatus_NoMemoryErr
);
1086 strcpy( item
->name
, inAddr
->ifa_name
);
1087 item
->multicastSocketRef
= kInvalidSocketRef
;
1088 item
->sendingSocketRef
= kInvalidSocketRef
;
1090 // Set up the multicast DNS (port 5353) socket for this interface.
1092 err
= SetupSocket( inMDNS
, inAddr
, MulticastDNSPort
, &socketRef
);
1093 require_noerr( err
, exit
);
1094 item
->multicastSocketRef
= socketRef
;
1096 // Set up the sending socket for this interface.
1098 err
= SetupSocket( inMDNS
, inAddr
, zeroIPPort
, &socketRef
);
1099 require_noerr( err
, exit
);
1100 item
->sendingSocketRef
= socketRef
;
1102 // Register this interface with mDNS.
1104 item
->hostSet
.InterfaceID
= (mDNSInterfaceID
) item
;
1105 item
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
1106 item
->hostSet
.ip
.ip
.v4
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1107 item
->hostSet
.mask
.type
= mDNSAddrType_IPv4
;
1108 item
->hostSet
.mask
.ip
.v4
.NotAnInteger
= mask
->sin_addr
.s_addr
;
1109 item
->hostSet
.ifname
[0] = 0;
1110 item
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1111 item
->hostSet
.McastTxRx
= mDNStrue
;
1113 err
= mDNS_RegisterInterface( inMDNS
, &item
->hostSet
, mDNSfalse
);
1114 require_noerr( err
, exit
);
1115 item
->hostRegistered
= mDNStrue
;
1117 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1118 item
->hostSet
.ip
.ip
.v4
.b
[ 0 ], item
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1119 item
->hostSet
.ip
.ip
.v4
.b
[ 2 ], item
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1129 TearDownInterface( inMDNS
, item
);
1131 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (name=%s, err=%ld)\n", inAddr
->ifa_name
, err
);
1135 //===========================================================================================================================
1136 // TearDownInterface
1137 //===========================================================================================================================
1139 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
)
1141 MDNSSocketRef socketRef
;
1146 // Deregister this interface with mDNS.
1148 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1149 inItem
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1150 inItem
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1152 if( inItem
->hostRegistered
)
1154 inItem
->hostRegistered
= mDNSfalse
;
1155 mDNS_DeregisterInterface( inMDNS
, &inItem
->hostSet
, mDNSfalse
);
1158 // Close the multicast socket.
1160 socketRef
= inItem
->multicastSocketRef
;
1161 inItem
->multicastSocketRef
= kInvalidSocketRef
;
1162 if( socketRef
!= kInvalidSocketRef
)
1164 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1168 // Close the sending socket.
1170 socketRef
= inItem
->sendingSocketRef
;
1171 inItem
->sendingSocketRef
= kInvalidSocketRef
;
1172 if( socketRef
!= kInvalidSocketRef
)
1174 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down sending socket %d\n", socketRef
);
1178 // Free the memory used by the interface info.
1181 return( mStatus_NoError
);
1184 //===========================================================================================================================
1186 //===========================================================================================================================
1190 mDNS
* const inMDNS
,
1191 const struct ifaddrs
* inAddr
,
1193 MDNSSocketRef
* outSocketRef
)
1196 MDNSSocketRef socketRef
;
1198 unsigned char optionByte
;
1199 struct ip_mreq mreq
;
1200 const struct sockaddr_in
* ipv4
;
1201 struct sockaddr_in addr
;
1204 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1207 check( inAddr
->ifa_addr
);
1208 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1209 check( outSocketRef
);
1211 // Set up a UDP socket for multicast DNS.
1213 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1214 require_errno_action( socketRef
, errno
, exit
, err
= mStatus_UnknownErr
);
1216 // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
1217 // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
1218 // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
1219 // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
1220 // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
1222 if( inPort
.NotAnInteger
!= zeroIPPort
.NotAnInteger
)
1224 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
1227 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1228 check_errno( err
, errno
);
1230 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1232 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1233 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1234 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1235 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1236 check_errno( err
, errno
);
1238 // Bind to the multicast DNS address and port 5353.
1240 memset( &addr
, 0, sizeof( addr
) );
1241 addr
.sin_family
= AF_INET
;
1242 addr
.sin_port
= inPort
.NotAnInteger
;
1243 addr
.sin_addr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1244 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1245 check_errno( err
, errno
);
1247 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
1248 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], ntohs( inPort
.NotAnInteger
), socketRef
);
1252 // Bind to the interface address and multicast DNS port.
1254 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1255 memset( &addr
, 0, sizeof( addr
) );
1256 addr
.sin_family
= AF_INET
;
1257 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1258 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1259 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1260 check_errno( err
, errno
);
1262 // Direct multicast packets to the specified interface.
1264 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1265 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1266 check_errno( err
, errno
);
1268 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1271 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1272 check_errno( err
, errno
);
1274 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1277 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &optionByte
, sizeof( optionByte
) );
1278 check_errno( err
, errno
);
1280 // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
1281 // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
1284 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
1286 option
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1287 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TOS
, (char *) &option
, sizeof( option
) );
1288 check_errno( err
, errno
);
1291 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
1292 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], socketRef
);
1297 *outSocketRef
= socketRef
;
1298 socketRef
= kInvalidSocketRef
;
1299 err
= mStatus_NoError
;
1302 if( socketRef
!= kInvalidSocketRef
)
1311 #pragma mark == Commands ==
1314 //===========================================================================================================================
1316 //===========================================================================================================================
1318 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1322 // Clean up any leftover command pipe.
1324 TearDownCommandPipe( inMDNS
);
1326 // Create the pipe device and open it.
1328 pipeDevCreate( kMDNSPipeName
, kMDNSPipeMessageQueueSize
, kMDNSPipeMessageSize
);
1330 inMDNS
->p
->commandPipe
= open( kMDNSPipeName
, O_RDWR
, 0 );
1331 require_errno_action( inMDNS
->p
->commandPipe
, errno
, exit
, err
= mStatus_UnsupportedErr
);
1333 err
= mStatus_NoError
;
1339 //===========================================================================================================================
1340 // TearDownCommandPipe
1341 //===========================================================================================================================
1343 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1345 if( inMDNS
->p
->commandPipe
!= ERROR
)
1347 close( inMDNS
->p
->commandPipe
);
1348 #ifdef _WRS_VXWORKS_5_X
1349 // pipeDevDelete is not defined in older versions of VxWorks
1350 pipeDevDelete( kMDNSPipeName
, FALSE
);
1352 inMDNS
->p
->commandPipe
= ERROR
;
1354 return( mStatus_NoError
);
1357 //===========================================================================================================================
1359 //===========================================================================================================================
1361 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1365 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1367 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1368 require_errno( err
, errno
, exit
);
1370 err
= mStatus_NoError
;
1376 //===========================================================================================================================
1378 //===========================================================================================================================
1380 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1383 MDNSPipeCommandCode commandCode
;
1385 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1387 // Read the command code from the pipe and dispatch it.
1389 err
= read( inMDNS
->p
->commandPipe
, &commandCode
, sizeof( commandCode
) );
1390 require_errno( err
, errno
, exit
);
1392 switch( commandCode
)
1394 case kMDNSPipeCommandCodeReschedule
:
1396 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
1398 dlog( kDebugLevelChatty
, DEBUG_NAME
"reschedule\n" );
1401 case kMDNSPipeCommandCodeReconfigure
:
1402 ProcessCommandReconfigure( inMDNS
);
1405 case kMDNSPipeCommandCodeQuit
:
1407 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
1409 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe quit command\n" );
1410 inMDNS
->p
->quit
= mDNStrue
;
1411 ++inMDNS
->p
->configID
;
1415 dlog( kDebugLevelError
, DEBUG_NAME
"unknown pipe command code (code=0x%08X)\n", commandCode
);
1416 err
= mStatus_BadParamErr
;
1420 err
= mStatus_NoError
;
1426 //===========================================================================================================================
1427 // ProcessCommandReconfigure
1428 //===========================================================================================================================
1430 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
)
1434 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe reconfigure command\n" );
1436 // Tear down the existing interfaces and set up new ones using the new IP info.
1438 mDNSPlatformLock( inMDNS
);
1440 err
= TearDownInterfaceList( inMDNS
);
1443 err
= SetupInterfaceList( inMDNS
);
1446 mDNSPlatformUnlock( inMDNS
);
1448 // Inform clients of the change.
1450 if( inMDNS
->MainCallback
)
1452 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1455 // Force mDNS to update.
1457 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
1459 // Bump the config ID so the main processing loop detects the configuration change.
1461 ++inMDNS
->p
->configID
;
1466 #pragma mark == Threads ==
1469 //===========================================================================================================================
1471 //===========================================================================================================================
1473 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
)
1478 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1481 // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
1482 // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
1483 // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
1485 task
= taskSpawn( kMDNSTaskName
, kMDNSTaskPriority
, 0, kMDNSTaskStackSize
, (FUNCPTR
) Task
,
1486 (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1487 require_action( task
!= ERROR
, exit
, err
= mStatus_NoMemoryErr
);
1489 err
= mStatus_NoError
;
1492 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld, id=%d)\n", err
, task
);
1496 //===========================================================================================================================
1498 //===========================================================================================================================
1500 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
)
1504 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread\n" );
1507 // Send a quit command to cause the thread to exit.
1509 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
1511 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
1513 if( inMDNS
->p
->quitEvent
)
1515 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
1518 err
= mStatus_NoError
;
1520 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread done (err=%ld)\n", err
);
1524 //===========================================================================================================================
1526 //===========================================================================================================================
1528 mDNSlocal
void Task( mDNS
*inMDNS
)
1532 MDNSInterfaceItem
* item
;
1535 struct timeval timeout
;
1537 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting\n" );
1540 // Set up everything up.
1542 err
= TaskInit( inMDNS
);
1543 require_noerr( err
, exit
);
1545 // Main Processing Loop.
1547 while( !inMDNS
->p
->quit
)
1549 // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
1550 // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
1552 TaskSetupReadSet( inMDNS
, &allReadSet
, &maxSocket
);
1553 configID
= inMDNS
->p
->configID
;
1554 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting processing loop (configID=%ld)\n", configID
);
1556 while( configID
== inMDNS
->p
->configID
)
1558 mDNSs32 nextTaskTime
;
1562 // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
1563 // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
1564 // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
1565 // processing packets. This introduces a window for a race condition because the thread wake-up and
1566 // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
1567 // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
1569 inMDNS
->p
->rescheduled
= 0;
1570 nextTaskTime
= mDNS_Execute( inMDNS
);
1571 TaskSetupTimeout( inMDNS
, nextTaskTime
, &timeout
);
1573 // Wait until something occurs (e.g. command, incoming packet, or timeout).
1575 readSet
= allReadSet
;
1576 n
= select( maxSocket
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1577 inMDNS
->p
->rescheduled
= 1;
1578 check_errno( n
, errno
);
1579 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"task select result = %d\n", n
);
1582 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1584 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS
) );
1588 // Scan the read set to determine if any sockets have something pending and process them.
1591 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1593 if( FD_ISSET( item
->multicastSocketRef
, &readSet
) )
1595 TaskProcessPacket( inMDNS
, item
, item
->multicastSocketRef
);
1600 // Check for a pending command and process it.
1602 if( FD_ISSET( inMDNS
->p
->commandPipe
, &readSet
) )
1604 ProcessCommand( inMDNS
);
1612 // Signal we've quit.
1614 check( inMDNS
->p
->quitEvent
);
1615 semGive( inMDNS
->p
->quitEvent
);
1617 dlog( kDebugLevelInfo
, DEBUG_NAME
"task ended\n" );
1620 //===========================================================================================================================
1622 //===========================================================================================================================
1624 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1628 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init\n" );
1629 check( inMDNS
->p
->readyEvent
);
1631 inMDNS
->p
->task
= taskIdSelf();
1633 err
= SetupCommandPipe( inMDNS
);
1634 require_noerr( err
, exit
);
1636 SetupNames( inMDNS
);
1638 err
= SetupInterfaceList( inMDNS
);
1639 require_noerr( err
, exit
);
1642 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1644 inMDNS
->p
->taskInitErr
= err
;
1645 semGive( inMDNS
->p
->readyEvent
);
1647 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init done (err=%ld)\n", err
);
1651 //===========================================================================================================================
1653 //===========================================================================================================================
1655 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
)
1657 MDNSInterfaceItem
* item
;
1660 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set\n" );
1662 check( outReadSet
);
1663 check( outMaxSocket
);
1665 // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
1666 // should never happen since we should always have at least one interface, but it's just to be safe.
1668 FD_ZERO( outReadSet
);
1671 // Add all the receiving sockets to the read set.
1673 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1675 FD_SET( item
->multicastSocketRef
, outReadSet
);
1676 if( item
->multicastSocketRef
> maxSocket
)
1678 maxSocket
= item
->multicastSocketRef
;
1682 // Add the command pipe to the read set.
1684 FD_SET( inMDNS
->p
->commandPipe
, outReadSet
);
1685 if( inMDNS
->p
->commandPipe
> maxSocket
)
1687 maxSocket
= inMDNS
->p
->commandPipe
;
1689 check( maxSocket
> 0 );
1690 *outMaxSocket
= maxSocket
;
1692 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set done (maxSocket=%d)\n", maxSocket
);
1695 //===========================================================================================================================
1697 //===========================================================================================================================
1699 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
)
1703 // Calculate how long to wait before performing idle processing.
1705 delta
= inNextTaskTime
- mDNS_TimeNow(inMDNS
);
1708 // The next task time is now or in the past. Set the timeout to fire immediately.
1710 outTimeout
->tv_sec
= 0;
1711 outTimeout
->tv_usec
= 0;
1715 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1716 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1718 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1719 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicrosecondsMultiplier
;
1721 // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
1723 if( outTimeout
->tv_usec
>= 1000000L )
1725 outTimeout
->tv_sec
+= 1;
1726 outTimeout
->tv_usec
= 0;
1730 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task in %ld:%ld seconds (%ld)\n",
1731 outTimeout
->tv_sec
, outTimeout
->tv_usec
, inNextTaskTime
);
1733 //===========================================================================================================================
1734 // TaskProcessPacket
1735 //===========================================================================================================================
1737 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
)
1741 struct sockaddr_in addr
;
1743 mDNSu8
* packetEndPtr
;
1749 // Receive the packet.
1751 addrSize
= sizeof( addr
);
1752 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1756 // Set up the src/dst/interface info.
1758 srcAddr
.type
= mDNSAddrType_IPv4
;
1759 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1760 srcPort
.NotAnInteger
= addr
.sin_port
;
1761 dstAddr
.type
= mDNSAddrType_IPv4
;
1762 dstAddr
.ip
.v4
= AllDNSLinkGroup_v4
.ip
.v4
;
1763 dstPort
= MulticastDNSPort
;
1765 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1766 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1767 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%hu\n",
1768 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1769 ntohs( srcPort
.NotAnInteger
) );
1770 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%hu\n",
1771 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1772 ntohs( dstPort
.NotAnInteger
) );
1773 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = 0x%08X\n", (int) inItem
->hostSet
.InterfaceID
);
1774 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1776 // Dispatch the packet to mDNS.
1778 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1779 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inItem
->hostSet
.InterfaceID
);
1784 inItem
->recvCounter
+= 1;
1785 inItem
->recvErrorCounter
+= ( n
< 0 );
1790 #pragma mark == Utilities ==
1793 #if( TARGET_NON_APPLE )
1794 //===========================================================================================================================
1795 // GenerateUniqueHostName
1797 // Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
1798 //===========================================================================================================================
1800 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
)
1802 DEBUG_UNUSED( ioSeed
);
1804 // $$$ Non-Apple Platforms: Fill in appropriate name for device.
1806 mDNSPlatformStrCopy( outName
, kMDNSDefaultName
);
1809 //===========================================================================================================================
1810 // GenerateUniqueDNSName
1812 // Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
1813 // implemented to return a unique name.
1814 //===========================================================================================================================
1816 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
)
1818 DEBUG_UNUSED( ioSeed
);
1820 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
1822 mDNSPlatformStrCopy( outName
, kMDNSDefaultName
);
1830 //===========================================================================================================================
1832 //===========================================================================================================================
1834 int getifaddrs( struct ifaddrs
**outAddrs
)
1837 struct ifaddrs
* head
;
1838 struct ifaddrs
** next
;
1839 struct ifaddrs
* ifa
;
1842 char ipString
[ INET_ADDR_LEN
];
1851 ifp
= ifIndexToIfp( i
);
1858 // Allocate and initialize the ifaddrs structure and attach it to the linked list.
1860 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1861 require_action( ifa
, exit
, err
= ENOMEM
);
1864 next
= &ifa
->ifa_next
;
1868 ifa
->ifa_name
= (char *) malloc( 16 );
1869 require_action( ifa
->ifa_name
, exit
, err
= ENOMEM
);
1871 n
= sprintf( ifa
->ifa_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
1872 require_action( n
< 16, exit
, err
= ENOBUFS
);
1874 // Fetch the address.
1876 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( struct sockaddr_in
) );
1877 require_action( ifa
->ifa_addr
, exit
, err
= ENOMEM
);
1879 ipString
[ 0 ] = '\0';
1880 #if( TARGET_NON_APPLE )
1881 err
= ifAddrGet( ifa
->ifa_name
, ipString
);
1882 require_noerr( err
, exit
);
1884 err
= ifAddrGetNonAlias( ifa
->ifa_name
, ipString
);
1885 require_noerr( err
, exit
);
1888 err
= sock_pton( ipString
, AF_INET
, ifa
->ifa_addr
, 0, NULL
);
1889 require_noerr( err
, exit
);
1893 ifa
->ifa_flags
= ifp
->if_flags
;
1908 freeifaddrs( head
);
1913 //===========================================================================================================================
1915 //===========================================================================================================================
1917 void freeifaddrs( struct ifaddrs
*inAddrs
)
1922 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
1924 for( p
= inAddrs
; p
; p
= q
)
1930 free( p
->ifa_name
);
1935 free( p
->ifa_addr
);
1938 if( p
->ifa_netmask
)
1940 free( p
->ifa_netmask
);
1941 p
->ifa_netmask
= NULL
;
1943 if( p
->ifa_dstaddr
)
1945 free( p
->ifa_dstaddr
);
1946 p
->ifa_dstaddr
= NULL
;
1950 free( p
->ifa_data
);
1957 //===========================================================================================================================
1959 //===========================================================================================================================
1961 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
1965 if( inFamily
== AF_INET
)
1967 struct sockaddr_in
* ipv4
;
1969 if( inAddrSize
== 0 )
1971 inAddrSize
= sizeof( struct sockaddr_in
);
1973 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1979 ipv4
= (struct sockaddr_in
*) outAddr
;
1980 err
= inet_aton( (char *) inString
, &ipv4
->sin_addr
);
1983 ipv4
->sin_family
= AF_INET
;
1986 *outAddrSize
= sizeof( struct sockaddr_in
);
1990 #if( defined( AF_INET6 ) )
1991 else if( inFamily
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2007 //===========================================================================================================================
2009 //===========================================================================================================================
2011 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
2013 const struct sockaddr
* addr
;
2015 addr
= (const struct sockaddr
*) inAddr
;
2016 if( addr
->sa_family
== AF_INET
)
2018 struct sockaddr_in
* ipv4
;
2020 if( inAddrSize
== 0 )
2022 inAddrSize
= sizeof( struct sockaddr_in
);
2024 if( inAddrSize
< sizeof( struct sockaddr_in
) )
2030 if( inBufferSize
< 16 )
2037 ipv4
= (struct sockaddr_in
*) addr
;
2038 inet_ntoa_b( ipv4
->sin_addr
, inBuffer
);
2040 #if( defined( AF_INET6 ) )
2041 else if( addr
->sa_family
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2043 errno
= EAFNOSUPPORT
;
2050 errno
= EAFNOSUPPORT
;
2061 #pragma mark == Debugging ==
2066 void mDNSShow( BOOL inShowRecords
);
2067 void mDNSShowRecords( void );
2068 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
);
2070 //===========================================================================================================================
2072 //===========================================================================================================================
2074 void mDNSShow( BOOL inShowRecords
)
2076 MDNSInterfaceItem
* item
;
2082 printf( "### mDNS not initialized\n" );
2088 printf( "\n-- mDNS globals --\n" );
2089 printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2090 printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2091 printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2092 printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2093 printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr
);
2094 printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier
);
2095 printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->lockID
);
2096 printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->readyEvent
);
2097 printf( " taskInitErr = %ld\n", gMDNSPtr
->p
->taskInitErr
);
2098 printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->quitEvent
);
2099 printf( " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2100 printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->task
);
2101 printf( " quit = %d\n", gMDNSPtr
->p
->quit
);
2102 printf( " configID = %ld\n", gMDNSPtr
->p
->configID
);
2103 printf( " rescheduled = %d\n", gMDNSPtr
->p
->rescheduled
);
2104 printf( " nicelabel = \"%.*s\"\n", gMDNSPtr
->nicelabel
.c
[ 0 ], (char *) &gMDNSPtr
->nicelabel
.c
[ 1 ] );
2105 printf( " hostLabel = \"%.*s\"\n", gMDNSPtr
->hostlabel
.c
[ 0 ], (char *) &gMDNSPtr
->hostlabel
.c
[ 1 ] );
2110 printf( "\n-- mDNS interfaces --\n" );
2112 for( item
= gMDNSPtr
->p
->interfaceList
; item
; item
= item
->next
)
2114 printf( " -- interface %u --\n", n
);
2115 printf( " name = \"%s\"\n", item
->name
);
2116 printf( " multicastSocketRef = %d\n", item
->multicastSocketRef
);
2117 printf( " sendingSocketRef = %d\n", item
->sendingSocketRef
);
2118 ip
= item
->hostSet
.ip
;
2119 printf( " hostSet.ip = %u.%u.%u.%u\n", ip
.ip
.v4
.b
[ 0 ], ip
.ip
.v4
.b
[ 1 ],
2120 ip
.ip
.v4
.b
[ 2 ], ip
.ip
.v4
.b
[ 3 ] );
2121 printf( " hostSet.advertise = %s\n", item
->hostSet
.Advertise
? "YES" : "NO" );
2122 printf( " hostRegistered = %s\n", item
->hostRegistered
? "YES" : "NO" );
2124 printf( " sendMulticastCounter = %d\n", item
->sendMulticastCounter
);
2125 printf( " sendUnicastCounter = %d\n", item
->sendUnicastCounter
);
2126 printf( " sendErrorCounter = %d\n", item
->sendErrorCounter
);
2127 printf( " recvCounter = %d\n", item
->recvCounter
);
2128 printf( " recvErrorCounter = %d\n", item
->recvErrorCounter
);
2129 printf( " recvLoopCounter = %d\n", item
->recvLoopCounter
);
2142 //===========================================================================================================================
2144 //===========================================================================================================================
2146 void mDNSShowRecords( void )
2148 MDNSInterfaceItem
* item
;
2150 AuthRecord
* record
;
2151 char name
[ MAX_ESCAPED_DOMAIN_NAME
];
2153 printf( "\n-- mDNS resource records --\n" );
2155 for( record
= gMDNSPtr
->ResourceRecords
; record
; record
= record
->next
)
2157 item
= (MDNSInterfaceItem
*) record
->resrec
.InterfaceID
;
2158 ConvertDomainNameToCString( &record
->resrec
.name
, name
);
2159 printf( " -- record %d --\n", n
);
2160 printf( " interface = 0x%08X (%s)\n", (int) item
, item
? item
->name
: "<any>" );
2161 printf( " name = \"%s\"\n", name
);
2168 //===========================================================================================================================
2170 //===========================================================================================================================
2172 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
)
2179 printf( "\nTXT record (%u bytes):\n\n", inTXTSize
);
2181 p
= (const mDNSu8
*) inTXT
;
2182 end
= p
+ inTXTSize
;
2188 if( ( p
+ size
) > end
)
2190 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
2193 printf( "%2d (%3d bytes): \"%.*s\"\n", i
, size
, size
, p
);