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.29 2006/08/14 23:25:18 cheshire
25 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
27 Revision 1.28 2006/03/19 02:00:12 cheshire
28 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
30 Revision 1.27 2004/12/17 23:37:49 cheshire
31 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
32 (and other repetitive configuration changes)
34 Revision 1.26 2004/10/28 02:00:35 cheshire
35 <rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
37 Revision 1.25 2004/10/16 00:17:01 cheshire
38 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
40 Revision 1.24 2004/09/21 21:02:56 cheshire
41 Set up ifname before calling mDNS_RegisterInterface()
43 Revision 1.23 2004/09/17 01:08:57 cheshire
44 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
45 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
46 declared in that file are ONLY appropriate to single-address-space embedded applications.
47 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
49 Revision 1.22 2004/09/17 00:19:11 cheshire
50 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
52 Revision 1.21 2004/09/16 00:24:50 cheshire
53 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
55 Revision 1.20 2004/09/14 23:42:36 cheshire
56 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
58 Revision 1.19 2004/09/14 23:16:09 cheshire
59 mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
61 Revision 1.18 2004/08/14 03:22:42 cheshire
62 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
63 Add GetUserSpecifiedDDNSName() routine
64 Convert ServiceRegDomain to domainname instead of C string
65 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
67 Revision 1.17 2004/07/29 19:26:03 ksekar
68 Plaform-level changes for NATPMP support
70 Revision 1.16 2004/04/22 05:11:28 bradley
71 Added mDNSPlatformUTC for TSIG signed dynamic updates.
73 Revision 1.15 2004/04/21 02:49:12 cheshire
74 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
76 Revision 1.14 2004/04/09 17:43:04 cheshire
77 Make sure to set the McastTxRx field so that duplicate suppression works correctly
79 Revision 1.13 2004/01/27 20:15:24 cheshire
80 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
82 Revision 1.12 2004/01/24 09:12:37 bradley
83 Avoid TOS socket options to workaround a TOS routing problem with VxWorks and multiple interfaces
84 when sending unicast responses, which resulted in packets going out the wrong interface.
86 Revision 1.11 2004/01/24 04:59:16 cheshire
87 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
89 Revision 1.10 2003/11/14 21:27:09 cheshire
90 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
91 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
93 Revision 1.9 2003/11/14 20:59:09 cheshire
94 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
95 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
97 Revision 1.8 2003/10/28 10:08:27 bradley
98 Removed legacy port 53 support as it is no longer needed.
100 Revision 1.7 2003/08/20 05:58:54 bradley
101 Removed dependence on modified mDNSCore: define structures/prototypes locally.
103 Revision 1.6 2003/08/18 23:19:05 cheshire
104 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
106 Revision 1.5 2003/08/15 00:05:04 bradley
107 Updated to use name/InterfaceID from new AuthRecord resrec field. Added output of new record sizes.
109 Revision 1.4 2003/08/14 02:19:55 cheshire
110 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
112 Revision 1.3 2003/08/12 19:56:27 cheshire
115 Revision 1.2 2003/08/05 23:58:34 cheshire
116 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
117 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
119 Revision 1.1 2003/08/02 10:06:48 bradley
120 mDNS platform plugin for VxWorks.
123 Notes for non-Apple platforms:
125 TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
129 - Add support for IPv6 (needs VxWorks IPv6 support).
132 // Set up the debug library to use the default category (see DebugServicesLite.h for details).
134 #if( !TARGET_NON_APPLE )
135 #define DEBUG_USE_DEFAULT_CATEGORY 1
144 #include <sys/types.h>
145 #include <arpa/inet.h>
147 #include <netinet/if_ether.h>
148 #include <netinet/in.h>
149 #include <netinet/ip.h>
150 #include <sys/ioctl.h>
151 #include <sys/socket.h>
158 #include "selectLib.h"
167 #if( !TARGET_NON_APPLE )
168 #include "ACP/ACPUtilities.h"
169 #include "Support/DebugServicesLite.h"
170 #include "Support/MiscUtilities.h"
173 #include "mDNSEmbeddedAPI.h"
175 #include "mDNSVxWorks.h"
178 #pragma mark == Preprocessor ==
181 //===========================================================================================================================
183 //===========================================================================================================================
185 #if( !TARGET_NON_APPLE )
186 debug_log_new_default_category( mdns
);
190 #pragma mark == Constants ==
193 //===========================================================================================================================
195 //===========================================================================================================================
197 #define DEBUG_NAME "[mDNS] "
199 #define kMDNSDefaultName "My-Device"
201 #define kMDNSTaskName "tMDNS"
202 #define kMDNSTaskPriority 102
203 #define kMDNSTaskStackSize 49152
205 #define kMDNSPipeName "/pipe/mDNS"
206 #define kMDNSPipeMessageQueueSize 32
207 #define kMDNSPipeMessageSize 1
209 #define kInvalidSocketRef -1
211 typedef uint8_t MDNSPipeCommandCode
;
214 kMDNSPipeCommandCodeInvalid
= 0,
215 kMDNSPipeCommandCodeReschedule
= 1,
216 kMDNSPipeCommandCodeReconfigure
= 2,
217 kMDNSPipeCommandCodeQuit
= 3
221 #pragma mark == Structures ==
224 //===========================================================================================================================
226 //===========================================================================================================================
228 typedef int MDNSSocketRef
;
230 struct MDNSInterfaceItem
232 MDNSInterfaceItem
* next
;
234 MDNSSocketRef multicastSocketRef
;
235 MDNSSocketRef sendingSocketRef
;
236 NetworkInterfaceInfo hostSet
;
237 mDNSBool hostRegistered
;
239 int sendMulticastCounter
;
240 int sendUnicastCounter
;
241 int sendErrorCounter
;
244 int recvErrorCounter
;
249 #pragma mark == Macros ==
252 //===========================================================================================================================
254 //===========================================================================================================================
256 #if( TARGET_NON_APPLE )
258 // Do-nothing versions of the debugging macros for non-Apple platforms.
260 #define check(assertion)
261 #define check_string( assertion, cstring )
262 #define check_noerr(err)
263 #define check_noerr_string( error, cstring )
264 #define check_errno( assertion, errno_value )
265 #define debug_string( cstring )
266 #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
267 #define require_string( assertion, label, string ) require(assertion, label)
268 #define require_quiet( assertion, label ) require( assertion, label )
269 #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
270 #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
271 #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
272 #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
273 #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
274 #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
275 #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
276 #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label; } while(0)
277 #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
279 #define dlog( ARGS... )
281 #define DEBUG_UNUSED( X ) (void)( X )
285 #pragma mark == Prototypes ==
288 //===========================================================================================================================
290 //===========================================================================================================================
292 // ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
294 extern struct ifnet
* ifIndexToIfp(int ifIndex
);
296 // Platform Internals
298 mDNSlocal
void SetupNames( mDNS
* const inMDNS
);
299 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
300 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
301 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
);
302 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
);
306 const struct ifaddrs
* inAddr
,
308 MDNSSocketRef
* outSocketRef
);
312 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
313 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
314 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
315 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
316 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
);
320 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
);
321 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
);
322 mDNSlocal
void Task( mDNS
*inMDNS
);
323 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
324 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
);
325 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
);
326 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
);
330 #if( TARGET_NON_APPLE )
331 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
);
332 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
);
335 // Platform Accessors
341 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
342 struct mDNSPlatformInterfaceInfo
348 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
349 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
356 #pragma mark == Globals ==
359 //===========================================================================================================================
361 //===========================================================================================================================
363 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
364 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
365 mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier
= 0;
369 mDNSs32 mDNSPlatformOneSecond
;
373 #pragma mark == Public APIs ==
376 //===========================================================================================================================
378 //===========================================================================================================================
380 void mDNSReconfigure( void )
382 // Send a "reconfigure" command to the MDNS task.
386 SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
392 #pragma mark == Platform Support ==
395 //===========================================================================================================================
397 //===========================================================================================================================
399 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
403 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init\n" );
405 // Initialize variables.
407 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
408 inMDNS
->p
= &gMDNSPlatformSupport
;
409 inMDNS
->p
->commandPipe
= ERROR
;
410 inMDNS
->p
->task
= ERROR
;
411 inMDNS
->p
->rescheduled
= 1; // Default to rescheduled until fully initialized.
412 mDNSPlatformOneSecond
= sysClkRateGet();
413 gMDNSTicksToMicrosecondsMultiplier
= ( 1000000L / mDNSPlatformOneSecond
);
415 // Allocate semaphores.
417 inMDNS
->p
->lockID
= semMCreate( SEM_Q_FIFO
);
418 require_action( inMDNS
->p
->lockID
, exit
, err
= mStatus_NoMemoryErr
);
420 inMDNS
->p
->readyEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
421 require_action( inMDNS
->p
->readyEvent
, exit
, err
= mStatus_NoMemoryErr
);
423 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
424 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
428 // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
429 // stack space issues. Some of the initialization may require a larger stack than the current task supports.
431 err
= SetupTask( inMDNS
);
432 require_noerr( err
, exit
);
434 err
= semTake( inMDNS
->p
->readyEvent
, WAIT_FOREVER
);
435 require_noerr( err
, exit
);
436 err
= inMDNS
->p
->taskInitErr
;
437 require_noerr( err
, exit
);
439 mDNSCoreInitComplete( inMDNS
, err
);
444 mDNSPlatformClose( inMDNS
);
446 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
450 //===========================================================================================================================
452 //===========================================================================================================================
454 void mDNSPlatformClose( mDNS
* const inMDNS
)
458 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close\n" );
461 // Tear everything down.
463 err
= TearDownTask( inMDNS
);
466 err
= TearDownInterfaceList( inMDNS
);
469 err
= TearDownCommandPipe( inMDNS
);
474 // Release semaphores.
476 if( inMDNS
->p
->quitEvent
)
478 semDelete( inMDNS
->p
->quitEvent
);
479 inMDNS
->p
->quitEvent
= 0;
481 if( inMDNS
->p
->readyEvent
)
483 semDelete( inMDNS
->p
->readyEvent
);
484 inMDNS
->p
->readyEvent
= 0;
486 if( inMDNS
->p
->lockID
)
488 semDelete( inMDNS
->p
->lockID
);
489 inMDNS
->p
->lockID
= 0;
492 dlog( kDebugLevelInfo
, DEBUG_NAME
"platform close done\n" );
495 //===========================================================================================================================
496 // mDNSPlatformSendUDP
497 //===========================================================================================================================
501 const mDNS
* const inMDNS
,
502 const void * const inMsg
,
503 const mDNSu8
* const inMsgEnd
,
504 mDNSInterfaceID inInterfaceID
,
505 const mDNSAddr
* inDstIP
,
506 mDNSIPPort inDstPort
)
509 MDNSInterfaceItem
* item
;
510 struct sockaddr_in addr
;
513 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
520 check( inInterfaceID
);
522 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
524 err
= mStatus_BadParamErr
;
529 // Make sure the InterfaceID is valid.
531 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
533 if( item
== (MDNSInterfaceItem
*) inInterfaceID
)
538 require_action( item
, exit
, err
= mStatus_NoSuchNameErr
);
543 item
= (MDNSInterfaceItem
*) inInterfaceID
;
544 check( item
->sendingSocketRef
!= kInvalidSocketRef
);
546 memset( &addr
, 0, sizeof( addr
) );
547 addr
.sin_family
= AF_INET
;
548 addr
.sin_port
= inDstPort
.NotAnInteger
;
549 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
551 n
= inMsgEnd
- ( (const mDNSu8
* const) inMsg
);
552 n
= sendto( item
->sendingSocketRef
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
553 check_errno( n
, errno
);
555 item
->sendErrorCounter
+= ( n
< 0 );
556 item
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
557 item
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
559 dlog( kDebugLevelChatty
, DEBUG_NAME
"sent (to=%u.%u.%u.%u:%hu)\n",
560 inDstIP
->ip
.v4
.b
[ 0 ], inDstIP
->ip
.v4
.b
[ 1 ], inDstIP
->ip
.v4
.b
[ 2 ], inDstIP
->ip
.v4
.b
[ 3 ],
561 htons( inDstPort
.NotAnInteger
) );
562 err
= mStatus_NoError
;
565 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
569 //===========================================================================================================================
570 // Connection-oriented (TCP) functions
571 //===========================================================================================================================
573 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
574 TCPConnectionCallback callback
, void *context
, int *descriptor
)
577 (void)dstport
; // Unused
578 (void)InterfaceID
; // Unused
579 (void)callback
; // Unused
580 (void)context
; // Unused
581 (void)descriptor
; // Unused
582 return(mStatus_UnsupportedErr
);
585 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
590 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
594 (void)buflen
; // Unused
598 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
606 //===========================================================================================================================
608 //===========================================================================================================================
610 void mDNSPlatformLock( const mDNS
* const inMDNS
)
612 check( inMDNS
->p
->lockID
);
614 if( inMDNS
->p
->lockID
)
616 #if( TARGET_NON_APPLE )
617 semTake( inMDNS
->p
->lockID
, WAIT_FOREVER
);
619 semTakeDeadlockDetect( inMDNS
->p
->lockID
, WAIT_FOREVER
);
624 //===========================================================================================================================
625 // mDNSPlatformUnlock
626 //===========================================================================================================================
628 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
632 check( inMDNS
->p
->lockID
);
633 check_string( inMDNS
->p
->task
!= ERROR
, "mDNS task not started" );
635 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
636 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
637 // (a) handle immediate work (if any) resulting from this API call
638 // (b) calculate the next sleep time between now and the next interesting event
640 if( ( mDNS_TimeNow(inMDNS
) - inMDNS
->NextScheduledEvent
) >= 0 )
642 // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
643 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
645 if( ( inMDNS
->p
->rescheduled
++ == 0 ) && ( taskIdSelf() != inMDNS
->p
->task
) )
647 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
651 if( inMDNS
->p
->lockID
)
653 semGive( inMDNS
->p
->lockID
);
657 //===========================================================================================================================
658 // mDNSPlatformStrLen
659 //===========================================================================================================================
661 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
665 return( (mDNSu32
) strlen( (const char *) inSrc
) );
668 //===========================================================================================================================
669 // mDNSPlatformStrCopy
670 //===========================================================================================================================
672 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
677 strcpy( (char *) inDst
, (const char*) inSrc
);
680 //===========================================================================================================================
681 // mDNSPlatformMemCopy
682 //===========================================================================================================================
684 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
689 memcpy( inDst
, inSrc
, inSize
);
692 //===========================================================================================================================
693 // mDNSPlatformMemSame
694 //===========================================================================================================================
696 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
701 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
704 //===========================================================================================================================
705 // mDNSPlatformMemZero
706 //===========================================================================================================================
708 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
712 memset( inDst
, 0, inSize
);
715 //===========================================================================================================================
716 // mDNSPlatformMemAllocate
717 //===========================================================================================================================
719 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
725 mem
= malloc( inSize
);
731 //===========================================================================================================================
732 // mDNSPlatformMemFree
733 //===========================================================================================================================
735 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
742 //===========================================================================================================================
743 // mDNSPlatformRandomSeed
744 //===========================================================================================================================
746 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
751 //===========================================================================================================================
752 // mDNSPlatformTimeInit
753 //===========================================================================================================================
755 mDNSexport mStatus
mDNSPlatformTimeInit( void )
757 // No special setup is required on VxWorks -- we just use tickGet().
758 return( mStatus_NoError
);
761 //===========================================================================================================================
762 // mDNSPlatformRawTime
763 //===========================================================================================================================
765 mDNSs32
mDNSPlatformRawTime( void )
767 return( (mDNSs32
) tickGet() );
770 //===========================================================================================================================
772 //===========================================================================================================================
774 mDNSexport mDNSs32
mDNSPlatformUTC( void )
779 //===========================================================================================================================
780 // mDNSPlatformInterfaceNameToID
781 //===========================================================================================================================
783 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
786 MDNSInterfaceItem
* ifd
;
792 // Search for an interface with the specified name,
794 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
796 if( strcmp( ifd
->name
, inName
) == 0 )
803 err
= mStatus_NoSuchNameErr
;
811 *outID
= (mDNSInterfaceID
) ifd
;
813 err
= mStatus_NoError
;
819 //===========================================================================================================================
820 // mDNSPlatformInterfaceIDToInfo
821 //===========================================================================================================================
823 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
826 MDNSInterfaceItem
* ifd
;
832 // Search for an interface with the specified ID,
834 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
836 if( ifd
== (MDNSInterfaceItem
*) inID
)
843 err
= mStatus_NoSuchNameErr
;
849 outInfo
->name
= ifd
->name
;
850 outInfo
->ip
= ifd
->hostSet
.ip
;
851 err
= mStatus_NoError
;
857 //===========================================================================================================================
859 //===========================================================================================================================
861 #if( MDNS_DEBUGMSGS )
862 mDNSexport
void debugf_( const char *format
, ... )
868 va_start( args
, format
);
869 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
872 dlog( kDebugLevelInfo
, "%s\n", buffer
);
876 //===========================================================================================================================
878 //===========================================================================================================================
880 #if( MDNS_DEBUGMSGS > 1 )
881 mDNSexport
void verbosedebugf_( const char *format
, ... )
887 va_start( args
, format
);
888 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), format
, args
);
891 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
895 //===========================================================================================================================
897 //===========================================================================================================================
899 void LogMsg( const char *inFormat
, ... )
905 va_start( args
, inFormat
);
906 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
909 dlog( kDebugLevelWarning
, "%s\n", buffer
);
914 #pragma mark == Platform Internals ==
917 //===========================================================================================================================
919 //===========================================================================================================================
921 mDNSlocal
void SetupNames( mDNS
* const inMDNS
)
923 char tempCString
[ 128 ];
924 mDNSu8 tempPString
[ 128 ];
927 // Set up the host name.
929 tempCString
[ 0 ] = '\0';
930 GenerateUniqueHostName( tempCString
, NULL
);
931 check( tempCString
[ 0 ] != '\0' );
932 if( tempCString
[ 0 ] == '\0' )
934 // No name so use the default.
936 strcpy( tempCString
, kMDNSDefaultName
);
938 inMDNS
->nicelabel
.c
[ 0 ] = strlen( tempCString
);
939 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempCString
, inMDNS
->nicelabel
.c
[ 0 ] );
940 check( inMDNS
->nicelabel
.c
[ 0 ] > 0 );
942 // Set up the DNS name.
944 tempCString
[ 0 ] = '\0';
945 GenerateUniqueDNSName( tempCString
, NULL
);
946 if( tempCString
[ 0 ] != '\0' )
948 tempPString
[ 0 ] = strlen( tempCString
);
949 memcpy( &tempPString
[ 1 ], tempCString
, tempPString
[ 0 ] );
950 namePtr
= tempPString
;
954 // No DNS name so use the host name.
956 namePtr
= inMDNS
->nicelabel
.c
;
958 ConvertUTF8PstringToRFC1034HostLabel( namePtr
, &inMDNS
->hostlabel
);
959 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
961 // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
963 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
965 check( inMDNS
->hostlabel
.c
[ 0 ] > 0 );
967 mDNS_SetFQDN( inMDNS
);
969 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
970 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
973 //===========================================================================================================================
974 // SetupInterfaceList
975 //===========================================================================================================================
977 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
980 struct ifaddrs
* addrs
;
984 MDNSInterfaceItem
** next
;
985 MDNSInterfaceItem
* item
;
989 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
992 // Tear down any existing interfaces that may be set up.
994 TearDownInterfaceList( inMDNS
);
995 inMDNS
->p
->interfaceList
= NULL
;
996 next
= &inMDNS
->p
->interfaceList
;
998 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
1000 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTOPOINT
;
1001 flagTest
= IFF_UP
| IFF_MULTICAST
;
1003 err
= getifaddrs( &addrs
);
1004 require_noerr( err
, exit
);
1006 for( p
= addrs
; p
; p
= p
->ifa_next
)
1008 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
1010 err
= SetupInterface( inMDNS
, p
, &item
);
1011 require_noerr( err
, exit
);
1017 err
= mStatus_NoError
;
1022 freeifaddrs( addrs
);
1026 TearDownInterfaceList( inMDNS
);
1028 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
1032 //===========================================================================================================================
1033 // TearDownInterfaceList
1034 //===========================================================================================================================
1036 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1038 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
1041 // Tear down all the interfaces.
1043 while( inMDNS
->p
->interfaceList
)
1045 MDNSInterfaceItem
* item
;
1047 item
= inMDNS
->p
->interfaceList
;
1048 inMDNS
->p
->interfaceList
= item
->next
;
1050 TearDownInterface( inMDNS
, item
);
1053 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
1054 return( mStatus_NoError
);
1057 //===========================================================================================================================
1059 //===========================================================================================================================
1061 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inAddr
, MDNSInterfaceItem
**outItem
)
1064 MDNSInterfaceItem
* item
;
1065 MDNSSocketRef socketRef
;
1066 const struct sockaddr_in
* ipv4
, *mask
;
1068 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface (name=%s)\n", inAddr
->ifa_name
);
1071 check( inAddr
->ifa_addr
);
1072 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1073 mask
= (const struct sockaddr_in
*) inAddr
->ifa_netmask
;
1076 // Allocate memory for the info item.
1078 item
= (MDNSInterfaceItem
*) calloc( 1, sizeof( *item
) );
1079 require_action( item
, exit
, err
= mStatus_NoMemoryErr
);
1080 strcpy( item
->name
, inAddr
->ifa_name
);
1081 item
->multicastSocketRef
= kInvalidSocketRef
;
1082 item
->sendingSocketRef
= kInvalidSocketRef
;
1084 // Set up the multicast DNS (port 5353) socket for this interface.
1086 err
= SetupSocket( inMDNS
, inAddr
, MulticastDNSPort
, &socketRef
);
1087 require_noerr( err
, exit
);
1088 item
->multicastSocketRef
= socketRef
;
1090 // Set up the sending socket for this interface.
1092 err
= SetupSocket( inMDNS
, inAddr
, zeroIPPort
, &socketRef
);
1093 require_noerr( err
, exit
);
1094 item
->sendingSocketRef
= socketRef
;
1096 // Register this interface with mDNS.
1098 item
->hostSet
.InterfaceID
= (mDNSInterfaceID
) item
;
1099 item
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
1100 item
->hostSet
.ip
.ip
.v4
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1101 item
->hostSet
.mask
.type
= mDNSAddrType_IPv4
;
1102 item
->hostSet
.mask
.ip
.v4
.NotAnInteger
= mask
->sin_addr
.s_addr
;
1103 item
->hostSet
.ifname
[0] = 0;
1104 item
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1105 item
->hostSet
.McastTxRx
= mDNStrue
;
1107 err
= mDNS_RegisterInterface( inMDNS
, &item
->hostSet
, mDNSfalse
);
1108 require_noerr( err
, exit
);
1109 item
->hostRegistered
= mDNStrue
;
1111 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1112 item
->hostSet
.ip
.ip
.v4
.b
[ 0 ], item
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1113 item
->hostSet
.ip
.ip
.v4
.b
[ 2 ], item
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1123 TearDownInterface( inMDNS
, item
);
1125 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (name=%s, err=%ld)\n", inAddr
->ifa_name
, err
);
1129 //===========================================================================================================================
1130 // TearDownInterface
1131 //===========================================================================================================================
1133 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, MDNSInterfaceItem
*inItem
)
1135 MDNSSocketRef socketRef
;
1140 // Deregister this interface with mDNS.
1142 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1143 inItem
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1144 inItem
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inItem
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1146 if( inItem
->hostRegistered
)
1148 inItem
->hostRegistered
= mDNSfalse
;
1149 mDNS_DeregisterInterface( inMDNS
, &inItem
->hostSet
, mDNSfalse
);
1152 // Close the multicast socket.
1154 socketRef
= inItem
->multicastSocketRef
;
1155 inItem
->multicastSocketRef
= kInvalidSocketRef
;
1156 if( socketRef
!= kInvalidSocketRef
)
1158 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1162 // Close the sending socket.
1164 socketRef
= inItem
->sendingSocketRef
;
1165 inItem
->sendingSocketRef
= kInvalidSocketRef
;
1166 if( socketRef
!= kInvalidSocketRef
)
1168 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down sending socket %d\n", socketRef
);
1172 // Free the memory used by the interface info.
1175 return( mStatus_NoError
);
1178 //===========================================================================================================================
1180 //===========================================================================================================================
1184 mDNS
* const inMDNS
,
1185 const struct ifaddrs
* inAddr
,
1187 MDNSSocketRef
* outSocketRef
)
1190 MDNSSocketRef socketRef
;
1192 unsigned char optionByte
;
1193 struct ip_mreq mreq
;
1194 const struct sockaddr_in
* ipv4
;
1195 struct sockaddr_in addr
;
1198 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1201 check( inAddr
->ifa_addr
);
1202 ipv4
= (const struct sockaddr_in
*) inAddr
->ifa_addr
;
1203 check( outSocketRef
);
1205 // Set up a UDP socket for multicast DNS.
1207 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1208 require_errno_action( socketRef
, errno
, exit
, err
= mStatus_UnknownErr
);
1210 // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
1211 // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
1212 // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
1213 // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
1214 // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
1216 if( inPort
.NotAnInteger
!= zeroIPPort
.NotAnInteger
)
1218 // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
1221 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1222 check_errno( err
, errno
);
1224 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1226 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1227 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1228 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1229 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1230 check_errno( err
, errno
);
1232 // Bind to the multicast DNS address and port 5353.
1234 memset( &addr
, 0, sizeof( addr
) );
1235 addr
.sin_family
= AF_INET
;
1236 addr
.sin_port
= inPort
.NotAnInteger
;
1237 addr
.sin_addr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1238 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1239 check_errno( err
, errno
);
1241 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
1242 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], ntohs( inPort
.NotAnInteger
), socketRef
);
1246 // Bind to the interface address and multicast DNS port.
1248 ip
.NotAnInteger
= ipv4
->sin_addr
.s_addr
;
1249 memset( &addr
, 0, sizeof( addr
) );
1250 addr
.sin_family
= AF_INET
;
1251 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1252 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1253 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1254 check_errno( err
, errno
);
1256 // Direct multicast packets to the specified interface.
1258 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1259 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1260 check_errno( err
, errno
);
1262 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1265 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1266 check_errno( err
, errno
);
1268 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1271 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &optionByte
, sizeof( optionByte
) );
1272 check_errno( err
, errno
);
1274 // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
1275 // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
1278 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
1280 option
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1281 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TOS
, (char *) &option
, sizeof( option
) );
1282 check_errno( err
, errno
);
1285 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
1286 inAddr
->ifa_name
, ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], socketRef
);
1291 *outSocketRef
= socketRef
;
1292 socketRef
= kInvalidSocketRef
;
1293 err
= mStatus_NoError
;
1296 if( socketRef
!= kInvalidSocketRef
)
1305 #pragma mark == Commands ==
1308 //===========================================================================================================================
1310 //===========================================================================================================================
1312 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1316 // Clean up any leftover command pipe.
1318 TearDownCommandPipe( inMDNS
);
1320 // Create the pipe device and open it.
1322 pipeDevCreate( kMDNSPipeName
, kMDNSPipeMessageQueueSize
, kMDNSPipeMessageSize
);
1324 inMDNS
->p
->commandPipe
= open( kMDNSPipeName
, O_RDWR
, 0 );
1325 require_errno_action( inMDNS
->p
->commandPipe
, errno
, exit
, err
= mStatus_UnsupportedErr
);
1327 err
= mStatus_NoError
;
1333 //===========================================================================================================================
1334 // TearDownCommandPipe
1335 //===========================================================================================================================
1337 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1339 if( inMDNS
->p
->commandPipe
!= ERROR
)
1341 close( inMDNS
->p
->commandPipe
);
1342 #ifdef _WRS_VXWORKS_5_X
1343 // pipeDevDelete is not defined in older versions of VxWorks
1344 pipeDevDelete( kMDNSPipeName
, FALSE
);
1346 inMDNS
->p
->commandPipe
= ERROR
;
1348 return( mStatus_NoError
);
1351 //===========================================================================================================================
1353 //===========================================================================================================================
1355 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1359 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1361 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1362 require_errno( err
, errno
, exit
);
1364 err
= mStatus_NoError
;
1370 //===========================================================================================================================
1372 //===========================================================================================================================
1374 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1377 MDNSPipeCommandCode commandCode
;
1379 require_action( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1381 // Read the command code from the pipe and dispatch it.
1383 err
= read( inMDNS
->p
->commandPipe
, &commandCode
, sizeof( commandCode
) );
1384 require_errno( err
, errno
, exit
);
1386 switch( commandCode
)
1388 case kMDNSPipeCommandCodeReschedule
:
1390 // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
1392 dlog( kDebugLevelChatty
, DEBUG_NAME
"reschedule\n" );
1395 case kMDNSPipeCommandCodeReconfigure
:
1396 ProcessCommandReconfigure( inMDNS
);
1399 case kMDNSPipeCommandCodeQuit
:
1401 // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
1403 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe quit command\n" );
1404 inMDNS
->p
->quit
= mDNStrue
;
1405 ++inMDNS
->p
->configID
;
1409 dlog( kDebugLevelError
, DEBUG_NAME
"unknown pipe command code (code=0x%08X)\n", commandCode
);
1410 err
= mStatus_BadParamErr
;
1414 err
= mStatus_NoError
;
1420 //===========================================================================================================================
1421 // ProcessCommandReconfigure
1422 //===========================================================================================================================
1424 mDNSlocal
void ProcessCommandReconfigure( mDNS
*inMDNS
)
1428 dlog( kDebugLevelVerbose
, DEBUG_NAME
"processing pipe reconfigure command\n" );
1430 // Tear down the existing interfaces and set up new ones using the new IP info.
1432 mDNSPlatformLock( inMDNS
);
1434 err
= TearDownInterfaceList( inMDNS
);
1437 err
= SetupInterfaceList( inMDNS
);
1440 mDNSPlatformUnlock( inMDNS
);
1442 // Inform clients of the change.
1444 if( inMDNS
->MainCallback
)
1446 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1449 // Force mDNS to update.
1451 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
1453 // Bump the config ID so the main processing loop detects the configuration change.
1455 ++inMDNS
->p
->configID
;
1460 #pragma mark == Threads ==
1463 //===========================================================================================================================
1465 //===========================================================================================================================
1467 mDNSlocal mStatus
SetupTask( mDNS
* const inMDNS
)
1472 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1475 // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
1476 // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
1477 // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
1479 task
= taskSpawn( kMDNSTaskName
, kMDNSTaskPriority
, 0, kMDNSTaskStackSize
, (FUNCPTR
) Task
,
1480 (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1481 require_action( task
!= ERROR
, exit
, err
= mStatus_NoMemoryErr
);
1483 err
= mStatus_NoError
;
1486 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld, id=%d)\n", err
, task
);
1490 //===========================================================================================================================
1492 //===========================================================================================================================
1494 mDNSlocal mStatus
TearDownTask( mDNS
* const inMDNS
)
1498 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread\n" );
1501 // Send a quit command to cause the thread to exit.
1503 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
1505 // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
1507 if( inMDNS
->p
->quitEvent
)
1509 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
1512 err
= mStatus_NoError
;
1514 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down thread done (err=%ld)\n", err
);
1518 //===========================================================================================================================
1520 //===========================================================================================================================
1522 mDNSlocal
void Task( mDNS
*inMDNS
)
1526 MDNSInterfaceItem
* item
;
1529 struct timeval timeout
;
1531 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting\n" );
1534 // Set up everything up.
1536 err
= TaskInit( inMDNS
);
1537 require_noerr( err
, exit
);
1539 // Main Processing Loop.
1541 while( !inMDNS
->p
->quit
)
1543 // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
1544 // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
1546 TaskSetupReadSet( inMDNS
, &allReadSet
, &maxSocket
);
1547 configID
= inMDNS
->p
->configID
;
1548 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task starting processing loop (configID=%ld)\n", configID
);
1550 while( configID
== inMDNS
->p
->configID
)
1552 mDNSs32 nextTaskTime
;
1556 // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
1557 // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
1558 // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
1559 // processing packets. This introduces a window for a race condition because the thread wake-up and
1560 // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
1561 // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
1563 inMDNS
->p
->rescheduled
= 0;
1564 nextTaskTime
= mDNS_Execute( inMDNS
);
1565 TaskSetupTimeout( inMDNS
, nextTaskTime
, &timeout
);
1567 // Wait until something occurs (e.g. command, incoming packet, or timeout).
1569 readSet
= allReadSet
;
1570 n
= select( maxSocket
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1571 inMDNS
->p
->rescheduled
= 1;
1572 check_errno( n
, errno
);
1573 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"task select result = %d\n", n
);
1576 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1578 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS
) );
1582 // Scan the read set to determine if any sockets have something pending and process them.
1585 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1587 if( FD_ISSET( item
->multicastSocketRef
, &readSet
) )
1589 TaskProcessPacket( inMDNS
, item
, item
->multicastSocketRef
);
1594 // Check for a pending command and process it.
1596 if( FD_ISSET( inMDNS
->p
->commandPipe
, &readSet
) )
1598 ProcessCommand( inMDNS
);
1606 // Signal we've quit.
1608 check( inMDNS
->p
->quitEvent
);
1609 semGive( inMDNS
->p
->quitEvent
);
1611 dlog( kDebugLevelInfo
, DEBUG_NAME
"task ended\n" );
1614 //===========================================================================================================================
1616 //===========================================================================================================================
1618 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1622 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init\n" );
1623 check( inMDNS
->p
->readyEvent
);
1625 inMDNS
->p
->task
= taskIdSelf();
1627 err
= SetupCommandPipe( inMDNS
);
1628 require_noerr( err
, exit
);
1630 SetupNames( inMDNS
);
1632 err
= SetupInterfaceList( inMDNS
);
1633 require_noerr( err
, exit
);
1636 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1638 inMDNS
->p
->taskInitErr
= err
;
1639 semGive( inMDNS
->p
->readyEvent
);
1641 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task init done (err=%ld)\n", err
);
1645 //===========================================================================================================================
1647 //===========================================================================================================================
1649 mDNSlocal
void TaskSetupReadSet( mDNS
*inMDNS
, fd_set
*outReadSet
, int *outMaxSocket
)
1651 MDNSInterfaceItem
* item
;
1654 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set\n" );
1656 check( outReadSet
);
1657 check( outMaxSocket
);
1659 // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
1660 // should never happen since we should always have at least one interface, but it's just to be safe.
1662 FD_ZERO( outReadSet
);
1665 // Add all the receiving sockets to the read set.
1667 for( item
= inMDNS
->p
->interfaceList
; item
; item
= item
->next
)
1669 FD_SET( item
->multicastSocketRef
, outReadSet
);
1670 if( item
->multicastSocketRef
> maxSocket
)
1672 maxSocket
= item
->multicastSocketRef
;
1676 // Add the command pipe to the read set.
1678 FD_SET( inMDNS
->p
->commandPipe
, outReadSet
);
1679 if( inMDNS
->p
->commandPipe
> maxSocket
)
1681 maxSocket
= inMDNS
->p
->commandPipe
;
1683 check( maxSocket
> 0 );
1684 *outMaxSocket
= maxSocket
;
1686 dlog( kDebugLevelVerbose
, DEBUG_NAME
"task setting up read set done (maxSocket=%d)\n", maxSocket
);
1689 //===========================================================================================================================
1691 //===========================================================================================================================
1693 mDNSlocal
void TaskSetupTimeout( mDNS
*inMDNS
, mDNSs32 inNextTaskTime
, struct timeval
*outTimeout
)
1697 // Calculate how long to wait before performing idle processing.
1699 delta
= inNextTaskTime
- mDNS_TimeNow(inMDNS
);
1702 // The next task time is now or in the past. Set the timeout to fire immediately.
1704 outTimeout
->tv_sec
= 0;
1705 outTimeout
->tv_usec
= 0;
1709 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1710 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1712 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1713 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicrosecondsMultiplier
;
1715 // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
1717 if( outTimeout
->tv_usec
>= 1000000L )
1719 outTimeout
->tv_sec
+= 1;
1720 outTimeout
->tv_usec
= 0;
1724 dlog( kDebugLevelChatty
, DEBUG_NAME
"next task in %ld:%ld seconds (%ld)\n",
1725 outTimeout
->tv_sec
, outTimeout
->tv_usec
, inNextTaskTime
);
1727 //===========================================================================================================================
1728 // TaskProcessPacket
1729 //===========================================================================================================================
1731 mDNSlocal
void TaskProcessPacket( mDNS
*inMDNS
, MDNSInterfaceItem
*inItem
, MDNSSocketRef inSocketRef
)
1735 struct sockaddr_in addr
;
1737 mDNSu8
* packetEndPtr
;
1743 // Receive the packet.
1745 addrSize
= sizeof( addr
);
1746 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1750 // Set up the src/dst/interface info.
1752 srcAddr
.type
= mDNSAddrType_IPv4
;
1753 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1754 srcPort
.NotAnInteger
= addr
.sin_port
;
1755 dstAddr
.type
= mDNSAddrType_IPv4
;
1756 dstAddr
.ip
.v4
= AllDNSLinkGroupv4
;
1757 dstPort
= MulticastDNSPort
;
1759 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1760 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1761 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%hu\n",
1762 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1763 ntohs( srcPort
.NotAnInteger
) );
1764 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%hu\n",
1765 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1766 ntohs( dstPort
.NotAnInteger
) );
1767 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = 0x%08X\n", (int) inItem
->hostSet
.InterfaceID
);
1768 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1770 // Dispatch the packet to mDNS.
1772 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1773 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inItem
->hostSet
.InterfaceID
);
1778 inItem
->recvCounter
+= 1;
1779 inItem
->recvErrorCounter
+= ( n
< 0 );
1784 #pragma mark == Utilities ==
1787 #if( TARGET_NON_APPLE )
1788 //===========================================================================================================================
1789 // GenerateUniqueHostName
1791 // Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
1792 //===========================================================================================================================
1794 mDNSlocal
void GenerateUniqueHostName( char *outName
, long *ioSeed
)
1796 DEBUG_UNUSED( ioSeed
);
1798 // $$$ Non-Apple Platforms: Fill in appropriate name for device.
1800 mDNSPlatformStrCopy( kMDNSDefaultName
, outName
);
1803 //===========================================================================================================================
1804 // GenerateUniqueDNSName
1806 // Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
1807 // implemented to return a unique name.
1808 //===========================================================================================================================
1810 mDNSlocal
void GenerateUniqueDNSName( char *outName
, long *ioSeed
)
1812 DEBUG_UNUSED( ioSeed
);
1814 // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
1816 mDNSPlatformStrCopy( kMDNSDefaultName
, outName
);
1824 //===========================================================================================================================
1826 //===========================================================================================================================
1828 int getifaddrs( struct ifaddrs
**outAddrs
)
1831 struct ifaddrs
* head
;
1832 struct ifaddrs
** next
;
1833 struct ifaddrs
* ifa
;
1836 char ipString
[ INET_ADDR_LEN
];
1845 ifp
= ifIndexToIfp( i
);
1852 // Allocate and initialize the ifaddrs structure and attach it to the linked list.
1854 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1855 require_action( ifa
, exit
, err
= ENOMEM
);
1858 next
= &ifa
->ifa_next
;
1862 ifa
->ifa_name
= (char *) malloc( 16 );
1863 require_action( ifa
->ifa_name
, exit
, err
= ENOMEM
);
1865 n
= sprintf( ifa
->ifa_name
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
1866 require_action( n
< 16, exit
, err
= ENOBUFS
);
1868 // Fetch the address.
1870 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( struct sockaddr_in
) );
1871 require_action( ifa
->ifa_addr
, exit
, err
= ENOMEM
);
1873 ipString
[ 0 ] = '\0';
1874 #if( TARGET_NON_APPLE )
1875 err
= ifAddrGet( ifa
->ifa_name
, ipString
);
1876 require_noerr( err
, exit
);
1878 err
= ifAddrGetNonAlias( ifa
->ifa_name
, ipString
);
1879 require_noerr( err
, exit
);
1882 err
= sock_pton( ipString
, AF_INET
, ifa
->ifa_addr
, 0, NULL
);
1883 require_noerr( err
, exit
);
1887 ifa
->ifa_flags
= ifp
->if_flags
;
1902 freeifaddrs( head
);
1907 //===========================================================================================================================
1909 //===========================================================================================================================
1911 void freeifaddrs( struct ifaddrs
*inAddrs
)
1916 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
1918 for( p
= inAddrs
; p
; p
= q
)
1924 free( p
->ifa_name
);
1929 free( p
->ifa_addr
);
1932 if( p
->ifa_netmask
)
1934 free( p
->ifa_netmask
);
1935 p
->ifa_netmask
= NULL
;
1937 if( p
->ifa_dstaddr
)
1939 free( p
->ifa_dstaddr
);
1940 p
->ifa_dstaddr
= NULL
;
1944 free( p
->ifa_data
);
1951 //===========================================================================================================================
1953 //===========================================================================================================================
1955 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
1959 if( inFamily
== AF_INET
)
1961 struct sockaddr_in
* ipv4
;
1963 if( inAddrSize
== 0 )
1965 inAddrSize
= sizeof( struct sockaddr_in
);
1967 if( inAddrSize
< sizeof( struct sockaddr_in
) )
1973 ipv4
= (struct sockaddr_in
*) outAddr
;
1974 err
= inet_aton( (char *) inString
, &ipv4
->sin_addr
);
1977 ipv4
->sin_family
= AF_INET
;
1980 *outAddrSize
= sizeof( struct sockaddr_in
);
1984 #if( defined( AF_INET6 ) )
1985 else if( inFamily
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2001 //===========================================================================================================================
2003 //===========================================================================================================================
2005 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
2007 const struct sockaddr
* addr
;
2009 addr
= (const struct sockaddr
*) inAddr
;
2010 if( addr
->sa_family
== AF_INET
)
2012 struct sockaddr_in
* ipv4
;
2014 if( inAddrSize
== 0 )
2016 inAddrSize
= sizeof( struct sockaddr_in
);
2018 if( inAddrSize
< sizeof( struct sockaddr_in
) )
2024 if( inBufferSize
< 16 )
2031 ipv4
= (struct sockaddr_in
*) addr
;
2032 inet_ntoa_b( ipv4
->sin_addr
, inBuffer
);
2034 #if( defined( AF_INET6 ) )
2035 else if( addr
->sa_family
== AF_INET6
) // $$$ TO DO: Add IPv6 support.
2037 errno
= EAFNOSUPPORT
;
2044 errno
= EAFNOSUPPORT
;
2055 #pragma mark == Debugging ==
2060 void mDNSShow( BOOL inShowRecords
);
2061 void mDNSShowRecords( void );
2062 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
);
2064 //===========================================================================================================================
2066 //===========================================================================================================================
2068 void mDNSShow( BOOL inShowRecords
)
2070 MDNSInterfaceItem
* item
;
2076 printf( "### mDNS not initialized\n" );
2082 printf( "\n-- mDNS globals --\n" );
2083 printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2084 printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2085 printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2086 printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2087 printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr
);
2088 printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier
);
2089 printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->lockID
);
2090 printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->readyEvent
);
2091 printf( " taskInitErr = %ld\n", gMDNSPtr
->p
->taskInitErr
);
2092 printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->quitEvent
);
2093 printf( " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2094 printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr
->p
->task
);
2095 printf( " quit = %d\n", gMDNSPtr
->p
->quit
);
2096 printf( " configID = %ld\n", gMDNSPtr
->p
->configID
);
2097 printf( " rescheduled = %d\n", gMDNSPtr
->p
->rescheduled
);
2098 printf( " nicelabel = \"%.*s\"\n", gMDNSPtr
->nicelabel
.c
[ 0 ], (char *) &gMDNSPtr
->nicelabel
.c
[ 1 ] );
2099 printf( " hostLabel = \"%.*s\"\n", gMDNSPtr
->hostlabel
.c
[ 0 ], (char *) &gMDNSPtr
->hostlabel
.c
[ 1 ] );
2104 printf( "\n-- mDNS interfaces --\n" );
2106 for( item
= gMDNSPtr
->p
->interfaceList
; item
; item
= item
->next
)
2108 printf( " -- interface %u --\n", n
);
2109 printf( " name = \"%s\"\n", item
->name
);
2110 printf( " multicastSocketRef = %d\n", item
->multicastSocketRef
);
2111 printf( " sendingSocketRef = %d\n", item
->sendingSocketRef
);
2112 ip
= item
->hostSet
.ip
;
2113 printf( " hostSet.ip = %u.%u.%u.%u\n", ip
.ip
.v4
.b
[ 0 ], ip
.ip
.v4
.b
[ 1 ],
2114 ip
.ip
.v4
.b
[ 2 ], ip
.ip
.v4
.b
[ 3 ] );
2115 printf( " hostSet.advertise = %s\n", item
->hostSet
.Advertise
? "YES" : "NO" );
2116 printf( " hostRegistered = %s\n", item
->hostRegistered
? "YES" : "NO" );
2118 printf( " sendMulticastCounter = %d\n", item
->sendMulticastCounter
);
2119 printf( " sendUnicastCounter = %d\n", item
->sendUnicastCounter
);
2120 printf( " sendErrorCounter = %d\n", item
->sendErrorCounter
);
2121 printf( " recvCounter = %d\n", item
->recvCounter
);
2122 printf( " recvErrorCounter = %d\n", item
->recvErrorCounter
);
2123 printf( " recvLoopCounter = %d\n", item
->recvLoopCounter
);
2136 //===========================================================================================================================
2138 //===========================================================================================================================
2140 void mDNSShowRecords( void )
2142 MDNSInterfaceItem
* item
;
2144 AuthRecord
* record
;
2145 char name
[ MAX_ESCAPED_DOMAIN_NAME
];
2147 printf( "\n-- mDNS resource records --\n" );
2149 for( record
= gMDNSPtr
->ResourceRecords
; record
; record
= record
->next
)
2151 item
= (MDNSInterfaceItem
*) record
->resrec
.InterfaceID
;
2152 ConvertDomainNameToCString( &record
->resrec
.name
, name
);
2153 printf( " -- record %d --\n", n
);
2154 printf( " interface = 0x%08X (%s)\n", (int) item
, item
? item
->name
: "<any>" );
2155 printf( " name = \"%s\"\n", name
);
2162 //===========================================================================================================================
2164 //===========================================================================================================================
2166 void mDNSShowTXT( const void *inTXT
, size_t inTXTSize
)
2173 printf( "\nTXT record (%u bytes):\n\n", inTXTSize
);
2175 p
= (const mDNSu8
*) inTXT
;
2176 end
= p
+ inTXTSize
;
2182 if( ( p
+ size
) > end
)
2184 printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
2187 printf( "%2d (%3d bytes): \"%.*s\"\n", i
, size
, size
, p
);