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.34 2009/01/13 05:31:35 mkrochma
25 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
27 Revision 1.33 2008/11/04 19:51:13 cheshire
28 Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
30 Revision 1.32 2008/10/03 18:25:18 cheshire
31 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
33 Revision 1.31 2007/03/22 18:31:49 cheshire
34 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
36 Revision 1.30 2006/12/19 22:43:56 cheshire
39 Revision 1.29 2006/08/14 23:25:18 cheshire
40 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
42 Revision 1.28 2006/03/19 02:00:12 cheshire
43 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
45 Revision 1.27 2004/12/17 23:37:49 cheshire
46 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
47 (and other repetitive configuration changes)
49 Revision 1.26 2004/10/28 02:00:35 cheshire
50 <rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
52 Revision 1.25 2004/10/16 00:17:01 cheshire
53 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
55 Revision 1.24 2004/09/21 21:02:56 cheshire
56 Set up ifname before calling mDNS_RegisterInterface()
58 Revision 1.23 2004/09/17 01:08:57 cheshire
59 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
60 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
61 declared in that file are ONLY appropriate to single-address-space embedded applications.
62 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
64 Revision 1.22 2004/09/17 00:19:11 cheshire
65 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
67 Revision 1.21 2004/09/16 00:24:50 cheshire
68 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
70 Revision 1.20 2004/09/14 23:42:36 cheshire
71 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
73 Revision 1.19 2004/09/14 23:16:09 cheshire
74 mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
76 Revision 1.18 2004/08/14 03:22:42 cheshire
77 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
78 Add GetUserSpecifiedDDNSName() routine
79 Convert ServiceRegDomain to domainname instead of C string
80 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
82 Revision 1.17 2004/07/29 19:26:03 ksekar
83 Plaform-level changes for NAT-PMP support
85 Revision 1.16 2004/04/22 05:11:28 bradley
86 Added mDNSPlatformUTC for TSIG signed dynamic updates.
88 Revision 1.15 2004/04/21 02:49:12 cheshire
89 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
91 Revision 1.14 2004/04/09 17:43:04 cheshire
92 Make sure to set the McastTxRx field so that duplicate suppression works correctly
94 Revision 1.13 2004/01/27 20:15:24 cheshire
95 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
97 Revision 1.12 2004/01/24 09:12:37 bradley
98 Avoid TOS socket options to workaround a TOS routing problem with VxWorks and multiple interfaces
99 when sending unicast responses, which resulted in packets going out the wrong interface.
101 Revision 1.11 2004/01/24 04:59:16 cheshire
102 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
104 Revision 1.10 2003/11/14 21:27:09 cheshire
105 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
106 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
108 Revision 1.9 2003/11/14 20:59:09 cheshire
109 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
110 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
112 Revision 1.8 2003/10/28 10:08:27 bradley
113 Removed legacy port 53 support as it is no longer needed.
115 Revision 1.7 2003/08/20 05:58:54 bradley
116 Removed dependence on modified mDNSCore: define structures/prototypes locally.
118 Revision 1.6 2003/08/18 23:19:05 cheshire
119 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
121 Revision 1.5 2003/08/15 00:05:04 bradley
122 Updated to use name/InterfaceID from new AuthRecord resrec field. Added output of new record sizes.
124 Revision 1.4 2003/08/14 02:19:55 cheshire
125 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
127 Revision 1.3 2003/08/12 19:56:27 cheshire
130 Revision 1.2 2003/08/05 23:58:34 cheshire
131 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
132 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
134 Revision 1.1 2003/08/02 10:06:48 bradley
135 mDNS platform plugin for VxWorks.
138 Notes for non-Apple platforms:
140 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
144 - Add support for IPv6 (needs VxWorks IPv6 support).
147 // Set up the debug library to use the default category (see DebugServicesLite.h for details).
149 #if( !TARGET_NON_APPLE )
150 #define DEBUG_USE_DEFAULT_CATEGORY 1
159 #include <sys/types.h>
160 #include <arpa/inet.h>
162 #include <netinet/if_ether.h>
163 #include <netinet/in.h>
164 #include <netinet/ip.h>
165 #include <sys/ioctl.h>
166 #include <sys/socket.h>
173 #include "selectLib.h"
182 #if( !TARGET_NON_APPLE )
183 #include "ACP/ACPUtilities.h"
184 #include "Support/DebugServicesLite.h"
185 #include "Support/MiscUtilities.h"
188 #include "mDNSEmbeddedAPI.h"
190 #include "mDNSVxWorks.h"
193 #pragma mark == Preprocessor ==
196 //===========================================================================================================================
198 //===========================================================================================================================
200 #if( !TARGET_NON_APPLE )
201 debug_log_new_default_category( mdns
);
205 #pragma mark == Constants ==
208 //===========================================================================================================================
210 //===========================================================================================================================
212 #define DEBUG_NAME "[mDNS] "
214 #define kMDNSDefaultName "My-Device"
216 #define kMDNSTaskName "tMDNS"
217 #define kMDNSTaskPriority 102
218 #define kMDNSTaskStackSize 49152
220 #define kMDNSPipeName "/pipe/mDNS"
221 #define kMDNSPipeMessageQueueSize 32
222 #define kMDNSPipeMessageSize 1
224 #define kInvalidSocketRef -1
226 typedef uint8_t MDNSPipeCommandCode
;
229 kMDNSPipeCommandCodeInvalid
= 0,
230 kMDNSPipeCommandCodeReschedule
= 1,
231 kMDNSPipeCommandCodeReconfigure
= 2,
232 kMDNSPipeCommandCodeQuit
= 3
236 #pragma mark == Structures ==
239 //===========================================================================================================================
241 //===========================================================================================================================
243 typedef int MDNSSocketRef
;
245 struct MDNSInterfaceItem
247 MDNSInterfaceItem
* next
;
249 MDNSSocketRef multicastSocketRef
;
250 MDNSSocketRef sendingSocketRef
;
251 NetworkInterfaceInfo hostSet
;
252 mDNSBool hostRegistered
;
254 int sendMulticastCounter
;
255 int sendUnicastCounter
;
256 int sendErrorCounter
;
259 int recvErrorCounter
;
264 #pragma mark == Macros ==
267 //===========================================================================================================================
269 //===========================================================================================================================
271 #if( TARGET_NON_APPLE )
273 // Do-nothing versions of the debugging macros for non-Apple platforms.
275 #define check(assertion)
276 #define check_string( assertion, cstring )
277 #define check_noerr(err)
278 #define check_noerr_string( error, cstring )
279 #define check_errno( assertion, errno_value )
280 #define debug_string( cstring )
281 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
282 #define require_string( assertion, label, string ) require(assertion, label)
283 #define require_quiet( assertion, label ) require( assertion, label )
284 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
285 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
286 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
287 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
288 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
289 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
290 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
291 #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label; } while(0)
292 #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
294 #define dlog( ARGS... )
296 #define DEBUG_UNUSED( X ) (void)( X )
300 #pragma mark == Prototypes ==
303 //===========================================================================================================================
305 //===========================================================================================================================
307 // ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
309 extern struct ifnet
* ifIndexToIfp(int ifIndex
);
311 // Platform Internals
313 mDNSlocal
void SetupNames( mDNS
* const inMDNS
);
314 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
315 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
316 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
);
317 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
);
321 const struct ifaddrs
* inAddr
,
323 MDNSSocketRef
* outSocketRef
);
327 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
328 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
329 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
330 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
331 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
);
335 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
);
336 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
);
337 mDNSlocal
void Task( mDNS
*inMDNS
);
338 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
339 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
);
340 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
);
341 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
);
345 #if( TARGET_NON_APPLE )
346 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
);
347 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
);
350 // Platform Accessors
356 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
357 struct mDNSPlatformInterfaceInfo
363 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
364 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
371 #pragma mark == Globals ==
374 //===========================================================================================================================
376 //===========================================================================================================================
378 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
379 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
380 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier
= 0;
384 mDNSs32 mDNSPlatformOneSecond
;
388 #pragma mark == Public APIs ==
391 //===========================================================================================================================
393 //===========================================================================================================================
395 void mDNSReconfigure( void )
397 // Send a "reconfigure" command to the MDNS task.
401 SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
407 #pragma mark == Platform Support ==
410 //===========================================================================================================================
412 //===========================================================================================================================
414 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
418 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init\n" );
420 // Initialize variables.
422 mDNSPlatformMemZero( &gMDNSPlatformSupport
, sizeof( gMDNSPlatformSupport
) );
423 inMDNS
->p
= &gMDNSPlatformSupport
;
424 inMDNS
->p
->commandPipe
= ERROR
;
425 inMDNS
->p
->task
= ERROR
;
426 inMDNS
->p
->rescheduled
= 1; // Default to rescheduled until fully initialized.
427 mDNSPlatformOneSecond
= sysClkRateGet();
428 gMDNSTicksToMicrosecondsMultiplier
= ( 1000000L / mDNSPlatformOneSecond
);
430 // Allocate semaphores.
432 inMDNS
->p
->lockID
= semMCreate( SEM_Q_FIFO
);
433 require_action( inMDNS
->p
->lockID
, exit
, err
= mStatus_NoMemoryErr
);
435 inMDNS
->p
->readyEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
436 require_action( inMDNS
->p
->readyEvent
, exit
, err
= mStatus_NoMemoryErr
);
438 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
439 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
443 // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
444 // stack space issues. Some of the initialization may require a larger stack than the current task supports.
446 err
= SetupTask( inMDNS
);
447 require_noerr( err
, exit
);
449 err
= semTake( inMDNS
->p
->readyEvent
, WAIT_FOREVER
);
450 require_noerr( err
, exit
);
451 err
= inMDNS
->p
->taskInitErr
;
452 require_noerr( err
, exit
);
454 mDNSCoreInitComplete( inMDNS
, err
);
459 mDNSPlatformClose( inMDNS
);
461 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
465 //===========================================================================================================================
467 //===========================================================================================================================
469 void mDNSPlatformClose( mDNS
* const inMDNS
)
473 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close\n" );
476 // Tear everything down.
478 err
= TearDownTask( inMDNS
);
481 err
= TearDownInterfaceList( inMDNS
);
484 err
= TearDownCommandPipe( inMDNS
);
489 // Release semaphores.
491 if( inMDNS
->p
->quitEvent
)
493 semDelete( inMDNS
->p
->quitEvent
);
494 inMDNS
->p
->quitEvent
= 0;
496 if( inMDNS
->p
->readyEvent
)
498 semDelete( inMDNS
->p
->readyEvent
);
499 inMDNS
->p
->readyEvent
= 0;
501 if( inMDNS
->p
->lockID
)
503 semDelete( inMDNS
->p
->lockID
);
504 inMDNS
->p
->lockID
= 0;
507 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close done\n" );
510 //===========================================================================================================================
511 // mDNSPlatformSendUDP
512 //===========================================================================================================================
516 const mDNS
* const inMDNS
,
517 const void * const inMsg
,
518 const mDNSu8
* const inMsgEnd
,
519 mDNSInterfaceID inInterfaceID
,
520 const mDNSAddr
* inDstIP
,
521 mDNSIPPort inDstPort
)
524 MDNSInterfaceItem
* item
;
525 struct sockaddr_in addr
;
528 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
535 check( inInterfaceID
);
537 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
539 err
= mStatus_BadParamErr
;
544 // Make sure the InterfaceID is valid.
546 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
548 if( item
== (MDNSInterfaceItem
*) inInterfaceID
)
553 require_action( item
, exit
, err
= mStatus_NoSuchNameErr
);
558 item
= (MDNSInterfaceItem
*) inInterfaceID
;
559 check( item
->sendingSocketRef
!= kInvalidSocketRef
);
561 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
562 addr
.sin_family
= AF_INET
;
563 addr
.sin_port
= inDstPort
.NotAnInteger
;
564 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
566 n
= inMsgEnd
- ( (const mDNSu8
* const) inMsg
);
567 n
= sendto( item
->sendingSocketRef
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
568 check_errno( n
, errno
);
570 item
->sendErrorCounter
+= ( n
< 0 );
571 item
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
572 item
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
574 dlog( kDebugLevelChatty
, DEBUG_NAME
"sent (to=%u.%u.%u.%u:%hu)\n",
575 inDstIP
->ip
.v4
.b
[ 0 ], inDstIP
->ip
.v4
.b
[ 1 ], inDstIP
->ip
.v4
.b
[ 2 ], inDstIP
->ip
.v4
.b
[ 3 ],
576 htons( inDstPort
.NotAnInteger
) );
577 err
= mStatus_NoError
;
580 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
584 //===========================================================================================================================
585 // Connection-oriented (TCP) functions
586 //===========================================================================================================================
588 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
589 TCPConnectionCallback callback
, void *context
, int *descriptor
)
592 (void)dstport
; // Unused
593 (void)InterfaceID
; // Unused
594 (void)callback
; // Unused
595 (void)context
; // Unused
596 (void)descriptor
; // Unused
597 return(mStatus_UnsupportedErr
);
600 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
605 mDNSexport
long mDNSPlatformReadTCP(int sd
, void *buf
, unsigned long buflen
)
609 (void)buflen
; // Unused
613 mDNSexport
long mDNSPlatformWriteTCP(int sd
, const char *msg
, unsigned long len
)
621 //===========================================================================================================================
623 //===========================================================================================================================
625 void mDNSPlatformLock( const mDNS
* const inMDNS
)
627 check( inMDNS
->p
->lockID
);
629 if( inMDNS
->p
->lockID
)
631 #if( TARGET_NON_APPLE )
632 semTake( inMDNS
->p
->lockID
, WAIT_FOREVER
);
634 semTakeDeadlockDetect( inMDNS
->p
->lockID
, WAIT_FOREVER
);
639 //===========================================================================================================================
640 // mDNSPlatformUnlock
641 //===========================================================================================================================
643 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
647 check( inMDNS
->p
->lockID
);
648 check_string( inMDNS
->p
->task
!= ERROR
, "mDNS task not started" );
650 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
651 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
652 // (a) handle immediate work (if any) resulting from this API call
653 // (b) calculate the next sleep time between now and the next interesting event
655 if( ( mDNS_TimeNow(inMDNS
) - inMDNS
->NextScheduledEvent
) >= 0 )
657 // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
658 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
660 if( ( inMDNS
->p
->rescheduled
++ == 0 ) && ( taskIdSelf() != inMDNS
->p
->task
) )
662 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
666 if( inMDNS
->p
->lockID
)
668 semGive( inMDNS
->p
->lockID
);
672 //===========================================================================================================================
673 // mDNSPlatformStrLen
674 //===========================================================================================================================
676 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
680 return( (mDNSu32
) strlen( (const char *) inSrc
) );
683 //===========================================================================================================================
684 // mDNSPlatformStrCopy
685 //===========================================================================================================================
687 void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
692 strcpy( (char *) inDst
, (const char*) inSrc
);
695 //===========================================================================================================================
696 // mDNSPlatformMemCopy
697 //===========================================================================================================================
699 void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
704 memcpy( inDst
, inSrc
, inSize
);
707 //===========================================================================================================================
708 // mDNSPlatformMemSame
709 //===========================================================================================================================
711 mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
716 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
719 //===========================================================================================================================
720 // mDNSPlatformMemZero
721 //===========================================================================================================================
723 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
727 memset( inDst
, 0, inSize
);
730 //===========================================================================================================================
731 // mDNSPlatformMemAllocate
732 //===========================================================================================================================
734 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
740 mem
= malloc( inSize
);
746 //===========================================================================================================================
747 // mDNSPlatformMemFree
748 //===========================================================================================================================
750 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
757 //===========================================================================================================================
758 // mDNSPlatformRandomSeed
759 //===========================================================================================================================
761 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
766 //===========================================================================================================================
767 // mDNSPlatformTimeInit
768 //===========================================================================================================================
770 mDNSexport mStatus
mDNSPlatformTimeInit( void )
772 // No special setup is required on VxWorks -- we just use tickGet().
773 return( mStatus_NoError
);
776 //===========================================================================================================================
777 // mDNSPlatformRawTime
778 //===========================================================================================================================
780 mDNSs32
mDNSPlatformRawTime( void )
782 return( (mDNSs32
) tickGet() );
785 //===========================================================================================================================
787 //===========================================================================================================================
789 mDNSexport mDNSs32
mDNSPlatformUTC( void )
794 //===========================================================================================================================
795 // mDNSPlatformInterfaceNameToID
796 //===========================================================================================================================
798 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
801 MDNSInterfaceItem
* ifd
;
807 // Search for an interface with the specified name,
809 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
811 if( strcmp( ifd
->name
, inName
) == 0 )
818 err
= mStatus_NoSuchNameErr
;
826 *outID
= (mDNSInterfaceID
) ifd
;
828 err
= mStatus_NoError
;
834 //===========================================================================================================================
835 // mDNSPlatformInterfaceIDToInfo
836 //===========================================================================================================================
838 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
841 MDNSInterfaceItem
* ifd
;
847 // Search for an interface with the specified ID,
849 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
851 if( ifd
== (MDNSInterfaceItem
*) inID
)
858 err
= mStatus_NoSuchNameErr
;
864 outInfo
->name
= ifd
->name
;
865 outInfo
->ip
= ifd
->hostSet
.ip
;
866 err
= mStatus_NoError
;
872 //===========================================================================================================================
874 //===========================================================================================================================
876 #if( MDNS_DEBUGMSGS )
877 mDNSexport
void debugf_( const char *format
, ... )
883 va_start( args
, format
);
884 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
887 dlog( kDebugLevelInfo
, "%s\n", buffer
);
891 //===========================================================================================================================
893 //===========================================================================================================================
895 #if( MDNS_DEBUGMSGS > 1 )
896 mDNSexport
void verbosedebugf_( const char *format
, ... )
902 va_start( args
, format
);
903 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
906 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
910 //===========================================================================================================================
912 //===========================================================================================================================
914 void LogMsg( const char *inFormat
, ... )
920 va_start( args
, inFormat
);
921 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
924 dlog( kDebugLevelWarning
, "%s\n", buffer
);
929 #pragma mark == Platform Internals ==
932 //===========================================================================================================================
934 //===========================================================================================================================
936 mDNSlocal
void SetupNames( mDNS
* const inMDNS
)
938 char tempCString
[ 128 ];
939 mDNSu8 tempPString
[ 128 ];
942 // Set up the host name.
944 tempCString
[ 0 ] = '\0';
945 GenerateUniqueHostName( tempCString
, NULL
);
946 check( tempCString
[ 0 ] != '\0' );
947 if( tempCString
[ 0 ] == '\0' )
949 // No name so use the default.
951 strcpy( tempCString
, kMDNSDefaultName
);
953 inMDNS
->nicelabel
.c
[ 0 ] = strlen( tempCString
);
954 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempCString
, inMDNS
->nicelabel
.c
[ 0 ] );
955 check( inMDNS
->nicelabel
.c
[ 0 ] > 0 );
957 // Set up the DNS name.
959 tempCString
[ 0 ] = '\0';
960 GenerateUniqueDNSName( tempCString
, NULL
);
961 if( tempCString
[ 0 ] != '\0' )
963 tempPString
[ 0 ] = strlen( tempCString
);
964 memcpy( &tempPString
[ 1 ], tempCString
, tempPString
[ 0 ] );
965 namePtr
= tempPString
;
969 // No DNS name so use the host name.
971 namePtr
= inMDNS
->nicelabel
.c
;
973 ConvertUTF8PstringToRFC1034HostLabel( namePtr
, &inMDNS
->hostlabel
);
974 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
976 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
978 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
980 check( inMDNS
->hostlabel
.c
[ 0 ] > 0 );
982 mDNS_SetFQDN( inMDNS
);
984 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
985 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
988 //===========================================================================================================================
989 // SetupInterfaceList
990 //===========================================================================================================================
992 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
995 struct ifaddrs
* addrs
;
999 MDNSInterfaceItem
** next
;
1000 MDNSInterfaceItem
* item
;
1004 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
1007 // Tear down any existing interfaces that may be set up.
1009 TearDownInterfaceList( inMDNS
);
1010 inMDNS
->p
->interfaceList
= NULL
;
1011 next
= &inMDNS
->p
->interfaceList
;
1013 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
1015 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTOPOINT
;
1016 flagTest
= IFF_UP
| IFF_MULTICAST
;
1018 err
= getifaddrs( &addrs
);
1019 require_noerr( err
, exit
);
1021 for( p
= addrs
; p
; p
= p
->ifa_next
)
1023 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
1025 err
= SetupInterface( inMDNS
, p
, &item
);
1026 require_noerr( err
, exit
);
1032 err
= mStatus_NoError
;
1037 freeifaddrs( addrs
);
1041 TearDownInterfaceList( inMDNS
);
1043 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
1047 //===========================================================================================================================
1048 // TearDownInterfaceList
1049 //===========================================================================================================================
1051 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1053 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
1056 // Tear down all the interfaces.
1058 while( inMDNS
->p
->interfaceList
)
1060 MDNSInterfaceItem
* item
;
1062 item
= inMDNS
->p
->interfaceList
;
1063 inMDNS
->p
->interfaceList
= item
->next
;
1065 TearDownInterface( inMDNS
, item
);
1068 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
1069 return( mStatus_NoError
);
1072 //===========================================================================================================================
1074 //===========================================================================================================================
1076 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
)
1079 MDNSInterfaceItem
* item
;
1080 MDNSSocketRef socketRef
;
1081 const struct sockaddr_in
* ipv4
, *mask
;
1083 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface (name=%s)\n", inAddr
->ifa_name
);
1086 check( inAddr
->ifa_addr
);
1087 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1088 mask
= (const struct sockaddr_in
*) inAddr
->ifa_netmask
;
1091 // Allocate memory for the info item.
1093 item
= (MDNSInterfaceItem
*) calloc( 1, sizeof( *item
) );
1094 require_action( item
, exit
, err
= mStatus_NoMemoryErr
);
1095 strcpy( item
->name
, inAddr
->ifa_name
);
1096 item
->multicastSocketRef
= kInvalidSocketRef
;
1097 item
->sendingSocketRef
= kInvalidSocketRef
;
1099 // Set up the multicast DNS (port 5353) socket for this interface.
1101 err
= SetupSocket( inMDNS
, inAddr
, MulticastDNSPort
, &socketRef
);
1102 require_noerr( err
, exit
);
1103 item
->multicastSocketRef
= socketRef
;
1105 // Set up the sending socket for this interface.
1107 err
= SetupSocket( inMDNS
, inAddr
, zeroIPPort
, &socketRef
);
1108 require_noerr( err
, exit
);
1109 item
->sendingSocketRef
= socketRef
;
1111 // Register this interface with mDNS.
1113 item
->hostSet
.InterfaceID
= (mDNSInterfaceID
) item
;
1114 item
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
1115 item
->hostSet
.ip
.ip
.v4
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1116 item
->hostSet
.mask
.type
= mDNSAddrType_IPv4
;
1117 item
->hostSet
.mask
.ip
.v4
.NotAnInteger
= mask
->sin_addr
.s_addr
;
1118 item
->hostSet
.ifname
[0] = 0;
1119 item
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1120 item
->hostSet
.McastTxRx
= mDNStrue
;
1122 err
= mDNS_RegisterInterface( inMDNS
, &item
->hostSet
, mDNSfalse
);
1123 require_noerr( err
, exit
);
1124 item
->hostRegistered
= mDNStrue
;
1126 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1127 item
->hostSet
.ip
.ip
.v4
.b
[ 0 ], item
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1128 item
->hostSet
.ip
.ip
.v4
.b
[ 2 ], item
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1138 TearDownInterface( inMDNS
, item
);
1140 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (name=%s, err=%ld)\n", inAddr
->ifa_name
, err
);
1144 //===========================================================================================================================
1145 // TearDownInterface
1146 //===========================================================================================================================
1148 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
)
1150 MDNSSocketRef socketRef
;
1155 // Deregister this interface with mDNS.
1157 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1158 inItem
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1159 inItem
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1161 if( inItem
->hostRegistered
)
1163 inItem
->hostRegistered
= mDNSfalse
;
1164 mDNS_DeregisterInterface( inMDNS
, &inItem
->hostSet
, mDNSfalse
);
1167 // Close the multicast socket.
1169 socketRef
= inItem
->multicastSocketRef
;
1170 inItem
->multicastSocketRef
= kInvalidSocketRef
;
1171 if( socketRef
!= kInvalidSocketRef
)
1173 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1177 // Close the sending socket.
1179 socketRef
= inItem
->sendingSocketRef
;
1180 inItem
->sendingSocketRef
= kInvalidSocketRef
;
1181 if( socketRef
!= kInvalidSocketRef
)
1183 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down sending socket %d\n", socketRef
);
1187 // Free the memory used by the interface info.
1190 return( mStatus_NoError
);
1193 //===========================================================================================================================
1195 //===========================================================================================================================
1199 mDNS
* const inMDNS
,
1200 const struct ifaddrs
* inAddr
,
1202 MDNSSocketRef
* outSocketRef
)
1205 MDNSSocketRef socketRef
;
1207 unsigned char optionByte
;
1208 struct ip_mreq mreq
;
1209 const struct sockaddr_in
* ipv4
;
1210 struct sockaddr_in addr
;
1213 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1216 check( inAddr
->ifa_addr
);
1217 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1218 check( outSocketRef
);
1220 // Set up a UDP socket for multicast DNS.
1222 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1223 require_errno_action( socketRef
, errno
, exit
, err
= mStatus_UnknownErr
);
1225 // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
1226 // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
1227 // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
1228 // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
1229 // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
1231 if( inPort
.NotAnInteger
!= zeroIPPort
.NotAnInteger
)
1233 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
1236 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1237 check_errno( err
, errno
);
1239 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1241 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1242 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1243 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1244 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1245 check_errno( err
, errno
);
1247 // Bind to the multicast DNS address and port 5353.
1249 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
1250 addr
.sin_family
= AF_INET
;
1251 addr
.sin_port
= inPort
.NotAnInteger
;
1252 addr
.sin_addr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1253 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1254 check_errno( err
, errno
);
1256 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
1257 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], ntohs( inPort
.NotAnInteger
), socketRef
);
1261 // Bind to the interface address and multicast DNS port.
1263 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1264 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
1265 addr
.sin_family
= AF_INET
;
1266 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1267 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1268 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1269 check_errno( err
, errno
);
1271 // Direct multicast packets to the specified interface.
1273 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1274 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1275 check_errno( err
, errno
);
1277 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1280 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1281 check_errno( err
, errno
);
1283 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1286 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &optionByte
, sizeof( optionByte
) );
1287 check_errno( err
, errno
);
1289 // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
1290 // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
1293 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
1295 option
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1296 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TOS
, (char *) &option
, sizeof( option
) );
1297 check_errno( err
, errno
);
1300 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
1301 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], socketRef
);
1306 *outSocketRef
= socketRef
;
1307 socketRef
= kInvalidSocketRef
;
1308 err
= mStatus_NoError
;
1311 if( socketRef
!= kInvalidSocketRef
)
1320 #pragma mark == Commands ==
1323 //===========================================================================================================================
1325 //===========================================================================================================================
1327 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1331 // Clean up any leftover command pipe.
1333 TearDownCommandPipe( inMDNS
);
1335 // Create the pipe device and open it.
1337 pipeDevCreate( kMDNSPipeName
, kMDNSPipeMessageQueueSize
, kMDNSPipeMessageSize
);
1339 inMDNS
->p
->commandPipe
= open( kMDNSPipeName
, O_RDWR
, 0 );
1340 require_errno_action( inMDNS
->p
->commandPipe
, errno
, exit
, err
= mStatus_UnsupportedErr
);
1342 err
= mStatus_NoError
;
1348 //===========================================================================================================================
1349 // TearDownCommandPipe
1350 //===========================================================================================================================
1352 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1354 if( inMDNS
->p
->commandPipe
!= ERROR
)
1356 close( inMDNS
->p
->commandPipe
);
1357 #ifdef _WRS_VXWORKS_5_X
1358 // pipeDevDelete is not defined in older versions of VxWorks
1359 pipeDevDelete( kMDNSPipeName
, FALSE
);
1361 inMDNS
->p
->commandPipe
= ERROR
;
1363 return( mStatus_NoError
);
1366 //===========================================================================================================================
1368 //===========================================================================================================================
1370 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1374 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1376 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1377 require_errno( err
, errno
, exit
);
1379 err
= mStatus_NoError
;
1385 //===========================================================================================================================
1387 //===========================================================================================================================
1389 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1392 MDNSPipeCommandCode commandCode
;
1394 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1396 // Read the command code from the pipe and dispatch it.
1398 err
= read( inMDNS
->p
->commandPipe
, &commandCode
, sizeof( commandCode
) );
1399 require_errno( err
, errno
, exit
);
1401 switch( commandCode
)
1403 case kMDNSPipeCommandCodeReschedule
:
1405 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
1407 dlog( kDebugLevelChatty
, DEBUG_NAME
"reschedule\n" );
1410 case kMDNSPipeCommandCodeReconfigure
:
1411 ProcessCommandReconfigure( inMDNS
);
1414 case kMDNSPipeCommandCodeQuit
:
1416 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
1418 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe quit command\n" );
1419 inMDNS
->p
->quit
= mDNStrue
;
1420 ++inMDNS
->p
->configID
;
1424 dlog( kDebugLevelError
, DEBUG_NAME
"unknown pipe command code (code=0x%08X)\n", commandCode
);
1425 err
= mStatus_BadParamErr
;
1429 err
= mStatus_NoError
;
1435 //===========================================================================================================================
1436 // ProcessCommandReconfigure
1437 //===========================================================================================================================
1439 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
)
1443 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe reconfigure command\n" );
1445 // Tear down the existing interfaces and set up new ones using the new IP info.
1447 mDNSPlatformLock( inMDNS
);
1449 err
= TearDownInterfaceList( inMDNS
);
1452 err
= SetupInterfaceList( inMDNS
);
1455 mDNSPlatformUnlock( inMDNS
);
1457 // Inform clients of the change.
1459 mDNS_ConfigChanged(m
);
1461 // Force mDNS to update.
1463 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
); // What is this for? Mac OS X does not do this
1465 // Bump the config ID so the main processing loop detects the configuration change.
1467 ++inMDNS
->p
->configID
;
1472 #pragma mark == Threads ==
1475 //===========================================================================================================================
1477 //===========================================================================================================================
1479 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
)
1484 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1487 // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
1488 // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
1489 // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
1491 task
= taskSpawn( kMDNSTaskName
, kMDNSTaskPriority
, 0, kMDNSTaskStackSize
, (FUNCPTR
) Task
,
1492 (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1493 require_action( task
!= ERROR
, exit
, err
= mStatus_NoMemoryErr
);
1495 err
= mStatus_NoError
;
1498 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld, id=%d)\n", err
, task
);
1502 //===========================================================================================================================
1504 //===========================================================================================================================
1506 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
)
1510 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread\n" );
1513 // Send a quit command to cause the thread to exit.
1515 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
1517 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
1519 if( inMDNS
->p
->quitEvent
)
1521 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
1524 err
= mStatus_NoError
;
1526 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread done (err=%ld)\n", err
);
1530 //===========================================================================================================================
1532 //===========================================================================================================================
1534 mDNSlocal
void Task( mDNS
*inMDNS
)
1538 MDNSInterfaceItem
* item
;
1541 struct timeval timeout
;
1543 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting\n" );
1546 // Set up everything up.
1548 err
= TaskInit( inMDNS
);
1549 require_noerr( err
, exit
);
1551 // Main Processing Loop.
1553 while( !inMDNS
->p
->quit
)
1555 // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
1556 // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
1558 TaskSetupReadSet( inMDNS
, &allReadSet
, &maxSocket
);
1559 configID
= inMDNS
->p
->configID
;
1560 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting processing loop (configID=%ld)\n", configID
);
1562 while( configID
== inMDNS
->p
->configID
)
1564 mDNSs32 nextTaskTime
;
1568 // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
1569 // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
1570 // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
1571 // processing packets. This introduces a window for a race condition because the thread wake-up and
1572 // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
1573 // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
1575 inMDNS
->p
->rescheduled
= 0;
1576 nextTaskTime
= mDNS_Execute( inMDNS
);
1577 TaskSetupTimeout( inMDNS
, nextTaskTime
, &timeout
);
1579 // Wait until something occurs (e.g. command, incoming packet, or timeout).
1581 readSet
= allReadSet
;
1582 n
= select( maxSocket
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1583 inMDNS
->p
->rescheduled
= 1;
1584 check_errno( n
, errno
);
1585 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"task select result = %d\n", n
);
1588 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1590 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS
) );
1594 // Scan the read set to determine if any sockets have something pending and process them.
1597 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1599 if( FD_ISSET( item
->multicastSocketRef
, &readSet
) )
1601 TaskProcessPacket( inMDNS
, item
, item
->multicastSocketRef
);
1606 // Check for a pending command and process it.
1608 if( FD_ISSET( inMDNS
->p
->commandPipe
, &readSet
) )
1610 ProcessCommand( inMDNS
);
1618 // Signal we've quit.
1620 check( inMDNS
->p
->quitEvent
);
1621 semGive( inMDNS
->p
->quitEvent
);
1623 dlog( kDebugLevelInfo
, DEBUG_NAME
"task ended\n" );
1626 //===========================================================================================================================
1628 //===========================================================================================================================
1630 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1634 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init\n" );
1635 check( inMDNS
->p
->readyEvent
);
1637 inMDNS
->p
->task
= taskIdSelf();
1639 err
= SetupCommandPipe( inMDNS
);
1640 require_noerr( err
, exit
);
1642 SetupNames( inMDNS
);
1644 err
= SetupInterfaceList( inMDNS
);
1645 require_noerr( err
, exit
);
1648 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1650 inMDNS
->p
->taskInitErr
= err
;
1651 semGive( inMDNS
->p
->readyEvent
);
1653 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init done (err=%ld)\n", err
);
1657 //===========================================================================================================================
1659 //===========================================================================================================================
1661 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
)
1663 MDNSInterfaceItem
* item
;
1666 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set\n" );
1668 check( outReadSet
);
1669 check( outMaxSocket
);
1671 // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
1672 // should never happen since we should always have at least one interface, but it's just to be safe.
1674 FD_ZERO( outReadSet
);
1677 // Add all the receiving sockets to the read set.
1679 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1681 FD_SET( item
->multicastSocketRef
, outReadSet
);
1682 if( item
->multicastSocketRef
> maxSocket
)
1684 maxSocket
= item
->multicastSocketRef
;
1688 // Add the command pipe to the read set.
1690 FD_SET( inMDNS
->p
->commandPipe
, outReadSet
);
1691 if( inMDNS
->p
->commandPipe
> maxSocket
)
1693 maxSocket
= inMDNS
->p
->commandPipe
;
1695 check( maxSocket
> 0 );
1696 *outMaxSocket
= maxSocket
;
1698 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set done (maxSocket=%d)\n", maxSocket
);
1701 //===========================================================================================================================
1703 //===========================================================================================================================
1705 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
)
1709 // Calculate how long to wait before performing idle processing.
1711 delta
= inNextTaskTime
- mDNS_TimeNow(inMDNS
);
1714 // The next task time is now or in the past. Set the timeout to fire immediately.
1716 outTimeout
->tv_sec
= 0;
1717 outTimeout
->tv_usec
= 0;
1721 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1722 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1724 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1725 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicrosecondsMultiplier
;
1727 // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
1729 if( outTimeout
->tv_usec
>= 1000000L )
1731 outTimeout
->tv_sec
+= 1;
1732 outTimeout
->tv_usec
= 0;
1736 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task in %ld:%ld seconds (%ld)\n",
1737 outTimeout
->tv_sec
, outTimeout
->tv_usec
, inNextTaskTime
);
1739 //===========================================================================================================================
1740 // TaskProcessPacket
1741 //===========================================================================================================================
1743 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
)
1747 struct sockaddr_in addr
;
1749 mDNSu8
* packetEndPtr
;
1755 // Receive the packet.
1757 addrSize
= sizeof( addr
);
1758 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1762 // Set up the src/dst/interface info.
1764 srcAddr
.type
= mDNSAddrType_IPv4
;
1765 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1766 srcPort
.NotAnInteger
= addr
.sin_port
;
1767 dstAddr
.type
= mDNSAddrType_IPv4
;
1768 dstAddr
.ip
.v4
= AllDNSLinkGroup_v4
.ip
.v4
;
1769 dstPort
= MulticastDNSPort
;
1771 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1772 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1773 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%hu\n",
1774 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1775 ntohs( srcPort
.NotAnInteger
) );
1776 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%hu\n",
1777 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1778 ntohs( dstPort
.NotAnInteger
) );
1779 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = 0x%08X\n", (int) inItem
->hostSet
.InterfaceID
);
1780 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1782 // Dispatch the packet to mDNS.
1784 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1785 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inItem
->hostSet
.InterfaceID
);
1790 inItem
->recvCounter
+= 1;
1791 inItem
->recvErrorCounter
+= ( n
< 0 );
1796 #pragma mark == Utilities ==
1799 #if( TARGET_NON_APPLE )
1800 //===========================================================================================================================
1801 // GenerateUniqueHostName
1803 // Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
1804 //===========================================================================================================================
1806 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
)
1808 DEBUG_UNUSED( ioSeed
);
1810 // $$$ Non-Apple Platforms: Fill in appropriate name for device.
1812 mDNSPlatformStrCopy( outName
, kMDNSDefaultName
);
1815 //===========================================================================================================================
1816 // GenerateUniqueDNSName
1818 // Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
1819 // implemented to return a unique name.
1820 //===========================================================================================================================
1822 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
)
1824 DEBUG_UNUSED( ioSeed
);
1826 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
1828 mDNSPlatformStrCopy( outName
, kMDNSDefaultName
);
1836 //===========================================================================================================================
1838 //===========================================================================================================================
1840 int getifaddrs( struct ifaddrs
**outAddrs
)
1843 struct ifaddrs
* head
;
1844 struct ifaddrs
** next
;
1845 struct ifaddrs
* ifa
;
1848 char ipString
[ INET_ADDR_LEN
];
1857 ifp
= ifIndexToIfp( i
);
1864 // Allocate and initialize the ifaddrs structure and attach it to the linked list.
1866 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1867 require_action( ifa
, exit
, err
= ENOMEM
);
1870 next
= &ifa
->ifa_next
;
1874 ifa
->ifa_name
= (char *) malloc( 16 );
1875 require_action( ifa
->ifa_name
, exit
, err
= ENOMEM
);
1877 n
= sprintf( ifa
->ifa_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
1878 require_action( n
< 16, exit
, err
= ENOBUFS
);
1880 // Fetch the address.
1882 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( struct sockaddr_in
) );
1883 require_action( ifa
->ifa_addr
, exit
, err
= ENOMEM
);
1885 ipString
[ 0 ] = '\0';
1886 #if( TARGET_NON_APPLE )
1887 err
= ifAddrGet( ifa
->ifa_name
, ipString
);
1888 require_noerr( err
, exit
);
1890 err
= ifAddrGetNonAlias( ifa
->ifa_name
, ipString
);
1891 require_noerr( err
, exit
);
1894 err
= sock_pton( ipString
, AF_INET
, ifa
->ifa_addr
, 0, NULL
);
1895 require_noerr( err
, exit
);
1899 ifa
->ifa_flags
= ifp
->if_flags
;
1914 freeifaddrs( head
);
1919 //===========================================================================================================================
1921 //===========================================================================================================================
1923 void freeifaddrs( struct ifaddrs
*inAddrs
)
1928 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
1930 for( p
= inAddrs
; p
; p
= q
)
1936 free( p
->ifa_name
);
1941 free( p
->ifa_addr
);
1944 if( p
->ifa_netmask
)
1946 free( p
->ifa_netmask
);
1947 p
->ifa_netmask
= NULL
;
1949 if( p
->ifa_dstaddr
)
1951 free( p
->ifa_dstaddr
);
1952 p
->ifa_dstaddr
= NULL
;
1956 free( p
->ifa_data
);
1963 //===========================================================================================================================
1965 //===========================================================================================================================
1967 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
1971 if( inFamily
== AF_INET
)
1973 struct sockaddr_in
* ipv4
;
1975 if( inAddrSize
== 0 )
1977 inAddrSize
= sizeof( struct sockaddr_in
);
1979 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1985 ipv4
= (struct sockaddr_in
*) outAddr
;
1986 err
= inet_aton( (char *) inString
, &ipv4
->sin_addr
);
1989 ipv4
->sin_family
= AF_INET
;
1992 *outAddrSize
= sizeof( struct sockaddr_in
);
1996 #if( defined( AF_INET6 ) )
1997 else if( inFamily
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2013 //===========================================================================================================================
2015 //===========================================================================================================================
2017 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
2019 const struct sockaddr
* addr
;
2021 addr
= (const struct sockaddr
*) inAddr
;
2022 if( addr
->sa_family
== AF_INET
)
2024 struct sockaddr_in
* ipv4
;
2026 if( inAddrSize
== 0 )
2028 inAddrSize
= sizeof( struct sockaddr_in
);
2030 if( inAddrSize
< sizeof( struct sockaddr_in
) )
2036 if( inBufferSize
< 16 )
2043 ipv4
= (struct sockaddr_in
*) addr
;
2044 inet_ntoa_b( ipv4
->sin_addr
, inBuffer
);
2046 #if( defined( AF_INET6 ) )
2047 else if( addr
->sa_family
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2049 errno
= EAFNOSUPPORT
;
2056 errno
= EAFNOSUPPORT
;
2067 #pragma mark == Debugging ==
2072 void mDNSShow( BOOL inShowRecords
);
2073 void mDNSShowRecords( void );
2074 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
);
2076 //===========================================================================================================================
2078 //===========================================================================================================================
2080 void mDNSShow( BOOL inShowRecords
)
2082 MDNSInterfaceItem
* item
;
2088 printf( "### mDNS not initialized\n" );
2094 printf( "\n-- mDNS globals --\n" );
2095 printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2096 printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2097 printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2098 printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2099 printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr
);
2100 printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier
);
2101 printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->lockID
);
2102 printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->readyEvent
);
2103 printf( " taskInitErr = %ld\n", gMDNSPtr
->p
->taskInitErr
);
2104 printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->quitEvent
);
2105 printf( " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2106 printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->task
);
2107 printf( " quit = %d\n", gMDNSPtr
->p
->quit
);
2108 printf( " configID = %ld\n", gMDNSPtr
->p
->configID
);
2109 printf( " rescheduled = %d\n", gMDNSPtr
->p
->rescheduled
);
2110 printf( " nicelabel = \"%.*s\"\n", gMDNSPtr
->nicelabel
.c
[ 0 ], (char *) &gMDNSPtr
->nicelabel
.c
[ 1 ] );
2111 printf( " hostLabel = \"%.*s\"\n", gMDNSPtr
->hostlabel
.c
[ 0 ], (char *) &gMDNSPtr
->hostlabel
.c
[ 1 ] );
2116 printf( "\n-- mDNS interfaces --\n" );
2118 for( item
= gMDNSPtr
->p
->interfaceList
; item
; item
= item
->next
)
2120 printf( " -- interface %u --\n", n
);
2121 printf( " name = \"%s\"\n", item
->name
);
2122 printf( " multicastSocketRef = %d\n", item
->multicastSocketRef
);
2123 printf( " sendingSocketRef = %d\n", item
->sendingSocketRef
);
2124 ip
= item
->hostSet
.ip
;
2125 printf( " hostSet.ip = %u.%u.%u.%u\n", ip
.ip
.v4
.b
[ 0 ], ip
.ip
.v4
.b
[ 1 ],
2126 ip
.ip
.v4
.b
[ 2 ], ip
.ip
.v4
.b
[ 3 ] );
2127 printf( " hostSet.advertise = %s\n", item
->hostSet
.Advertise
? "YES" : "NO" );
2128 printf( " hostRegistered = %s\n", item
->hostRegistered
? "YES" : "NO" );
2130 printf( " sendMulticastCounter = %d\n", item
->sendMulticastCounter
);
2131 printf( " sendUnicastCounter = %d\n", item
->sendUnicastCounter
);
2132 printf( " sendErrorCounter = %d\n", item
->sendErrorCounter
);
2133 printf( " recvCounter = %d\n", item
->recvCounter
);
2134 printf( " recvErrorCounter = %d\n", item
->recvErrorCounter
);
2135 printf( " recvLoopCounter = %d\n", item
->recvLoopCounter
);
2148 //===========================================================================================================================
2150 //===========================================================================================================================
2152 void mDNSShowRecords( void )
2154 MDNSInterfaceItem
* item
;
2156 AuthRecord
* record
;
2157 char name
[ MAX_ESCAPED_DOMAIN_NAME
];
2159 printf( "\n-- mDNS resource records --\n" );
2161 for( record
= gMDNSPtr
->ResourceRecords
; record
; record
= record
->next
)
2163 item
= (MDNSInterfaceItem
*) record
->resrec
.InterfaceID
;
2164 ConvertDomainNameToCString( &record
->resrec
.name
, name
);
2165 printf( " -- record %d --\n", n
);
2166 printf( " interface = 0x%08X (%s)\n", (int) item
, item
? item
->name
: "<any>" );
2167 printf( " name = \"%s\"\n", name
);
2174 //===========================================================================================================================
2176 //===========================================================================================================================
2178 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
)
2185 printf( "\nTXT record (%u bytes):\n\n", inTXTSize
);
2187 p
= (const mDNSu8
*) inTXT
;
2188 end
= p
+ inTXTSize
;
2194 if( ( p
+ size
) > end
)
2196 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
2199 printf( "%2d (%3d bytes): \"%.*s\"\n", i
, size
, size
, p
);