2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.22.2.1 2004/04/03 05:26:07 bradley
27 Integrated changes from TOT to remove legacy port 53 support.
29 Revision 1.24 2003/10/24 23:23:02 bradley
30 Removed legacy port 53 support as it is no longer needed.
32 Revision 1.23 2003/10/14 03:26:12 bradley
33 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
35 Revision 1.22 2003/08/20 06:21:25 bradley
36 Updated to latest internal version of the Rendezvous for Windows platform plugin: Added support
37 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
38 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
39 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
40 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
41 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
42 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
43 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
44 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
46 Revision 1.21 2003/08/18 23:09:57 cheshire
47 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
49 Revision 1.20 2003/08/12 19:56:27 cheshire
52 Revision 1.19 2003/08/05 23:58:18 cheshire
53 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
54 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
56 Revision 1.18 2003/07/23 21:16:30 cheshire
57 Removed a couple of debugfs
59 Revision 1.17 2003/07/23 02:23:01 cheshire
60 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
61 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
63 Revision 1.16 2003/07/19 03:15:16 cheshire
64 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
65 and add the obvious trivial implementations to each platform support layer
67 Revision 1.15 2003/07/02 21:20:04 cheshire
68 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
70 Revision 1.14 2003/05/26 03:21:30 cheshire
71 Tidy up address structure naming:
72 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
73 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
74 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
76 Revision 1.13 2003/05/26 03:01:28 cheshire
77 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
79 Revision 1.12 2003/05/06 21:06:05 cheshire
80 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
82 Revision 1.11 2003/05/06 00:00:51 cheshire
83 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
85 Revision 1.10 2003/04/29 00:06:09 cheshire
86 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
88 Revision 1.9 2003/04/26 02:40:01 cheshire
89 Add void LogMsg( const char *format, ... )
91 Revision 1.8 2003/03/22 02:57:44 cheshire
92 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
94 Revision 1.7 2003/03/15 04:40:38 cheshire
95 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
97 Revision 1.6 2003/02/21 01:54:10 cheshire
98 Bug #: 3099194 mDNSResponder needs performance improvements
99 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
101 Revision 1.5 2003/02/20 00:59:03 cheshire
102 Brought Windows code up to date so it complies with
103 Josh Graessley's interface changes for IPv6 support.
104 (Actual support for IPv6 on Windows will come later.)
106 Revision 1.4 2002/09/21 20:44:54 zarzycki
109 Revision 1.3 2002/09/20 05:50:45 bradley
110 Multicast DNS platform plugin for Win32
114 #if( defined( _MSC_VER ) )
115 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
118 #if( !defined( WIN32_LEAN_AND_MEAN ) )
119 #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
129 #include <winsock2.h>
130 #include <Ws2tcpip.h>
132 #if( !defined( _WIN32_WCE ) ) // Windows CE does not have process.h.
140 #include "mDNSClientAPI.h"
141 #include "mDNSPlatformFunctions.h"
143 #include "mDNSWin32.h"
146 #pragma mark == Constants ==
149 //===========================================================================================================================
151 //===========================================================================================================================
153 #define DEBUG_NAME "[mDNS] "
155 #if( !defined( MDNS_DEBUG_SIGNATURE ) )
156 #define MDNS_DEBUG_SIGNATURE "mDNS"
159 #define kMDNSDefaultName "My Computer"
161 #define kWinSockMajorMin 2
162 #define kWinSockMinorMin 2
164 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
165 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
166 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
167 #define kWaitListFixedItemCount 3
170 #pragma mark == Macros - Debug ==
173 //===========================================================================================================================
175 //===========================================================================================================================
177 #define MDNS_UNUSED( X ) (void)( X )
179 #define kDebugLevelMask 0x0000FFFFL
180 #define kDebugLevelChatty 100L
181 #define kDebugLevelVerbose 500L
182 #define kDebugLevelTrace 800L
183 #define kDebugLevelInfo 1000L
184 #define kDebugLevelRareInfo 2000L
185 #define kDebugLevelNotice 3000L
186 #define kDebugLevelWarning 4000L
187 #define kDebugLevelAllowedError 5000L
188 #define kDebugLevelAssert 6000L
189 #define kDebugLevelRequire 7000L
190 #define kDebugLevelError 8000L
191 #define kDebugLevelCritical 9000L
192 #define kDebugLevelCriticalError kDebugLevelCritical // DEPRECATED
193 #define kDebugLevelAlert 10000L
194 #define kDebugLevelEmergency 11000L
195 #define kDebugLevelTragic 12000L
196 #define kDebugLevelAny 0x0000FFFFL
198 #if( defined( __MWERKS__ ) || defined( __GNUC__ ) )
199 #define __ROUTINE__ __FUNCTION__
201 // Apple and Symantec compilers don't support the C99/GCC extensions yet.
203 #define __ROUTINE__ NULL
206 #if( MDNS_DEBUGMSGS )
207 #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION ) \
208 mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, 0, ( ASSERT_STRING ), NULL, ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
210 #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION ) \
211 mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, ( ERR ), ( ASSERT_STRING ), ( ERROR_STRING ), \
212 ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
214 #define dlog mDNSPlatformDebugLog
216 #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION )
218 #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION )
220 #define dlog while( 0 )
224 /// The following debugging macros emulate those available on Mac OS in AssertMacros.h/Debugging.h.
232 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
236 #define check_noerr( ERR ) \
238 if( ( ERR ) != 0 ) { \
239 debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
243 #define check_errno( ERR, ERRNO ) \
247 localErr = (int)( ERR ); \
248 if( localErr < 0 ) { \
251 localErrno = ( ERRNO ); \
252 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
253 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
259 #define require( X, LABEL ) \
262 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
267 #define require_quiet( X, LABEL ) \
274 #define require_action( X, LABEL, ACTION ) \
277 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
283 #define require_action_quiet( X, LABEL, ACTION ) \
291 #define require_noerr( ERR, LABEL ) \
293 if( ( ERR ) != 0 ) { \
294 debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
299 #define require_noerr_quiet( ERR, LABEL ) \
301 if( ( ERR ) != 0 ) { \
306 #define require_errno( ERR, ERRNO, LABEL ) \
310 localErr = (int)( ERR ); \
311 if( localErr < 0 ) { \
314 localErrno = ( ERRNO ); \
315 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
316 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
321 #define require_errno_action( ERR, ERRNO, LABEL, ACTION ) \
325 localErr = (int)( ERR ); \
326 if( localErr < 0 ) { \
329 localErrno = ( ERRNO ); \
330 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
331 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
338 #pragma mark == Macros - General ==
341 //===========================================================================================================================
343 //===========================================================================================================================
345 #define kInvalidSocketRef INVALID_SOCKET
346 #define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
347 #define close_compat( X ) closesocket( X )
348 #define errno_compat() WSAGetLastError()
350 // _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking
351 // resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to
352 // CreateThread on Windows CE.
354 #if( defined( _WIN32_WCE ) )
355 #define _beginthreadex( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR ) \
356 CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS, \
357 (LPDWORD) THREAD_ID_PTR )
359 #define _endthreadex( RESULT )
363 #pragma mark == Prototypes ==
366 //===========================================================================================================================
368 //===========================================================================================================================
370 #if( MDNS_DEBUGMSGS )
371 mDNSlocal
void mDNSPlatformDebugLog( unsigned long inLevel
, const char *inFormat
, ... );
373 mDNSPlatformPrintAssert(
374 const char * inSignature
,
376 const char * inAssertionString
,
377 const char * inErrorString
,
378 const char * inFileName
,
379 unsigned long inLineNumber
,
380 const char * inFunction
);
383 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
384 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
385 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
386 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
387 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
388 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct sockaddr_in
*inAddress
, mDNSInterfaceData
**outIFD
);
389 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
390 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
,
391 const struct sockaddr_in
* inAddress
,
392 SocketRef
* outSocketRef
);
393 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
394 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
396 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
397 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
398 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
399 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
400 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
401 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSocketRef
);
402 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
404 // Platform Accessors
410 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
411 struct mDNSPlatformInterfaceInfo
417 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
418 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
425 #pragma mark == Globals ==
428 //===========================================================================================================================
430 //===========================================================================================================================
432 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
433 mDNSs32 mDNSPlatformOneSecond
= 0;
435 #if( MDNS_DEBUGMSGS )
436 mDNSlocal
unsigned long gDebugLevel
= kDebugLevelInfo
+ 1;
441 #pragma mark == Platform Support APIs ==
444 //===========================================================================================================================
446 //===========================================================================================================================
448 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
454 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform init\n" );
456 // Initialize variables.
458 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
459 inMDNS
->p
= &gMDNSPlatformSupport
;
460 inMDNS
->p
->interfaceListChangedSocketRef
= kInvalidSocketRef
;
461 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time.
463 // Set everything up.
465 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
466 require_noerr( err
, exit
);
468 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
469 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
471 err
= SetupSynchronizationObjects( inMDNS
);
472 require_noerr( err
, exit
);
474 err
= SetupThread( inMDNS
);
475 require_noerr( err
, exit
);
479 mDNSCoreInitComplete( inMDNS
, err
);
484 mDNSPlatformClose( inMDNS
);
486 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
490 //===========================================================================================================================
492 //===========================================================================================================================
494 void mDNSPlatformClose( mDNS
* const inMDNS
)
498 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform close\n" );
501 // Tear everything down in reverse order to how it was set up.
503 err
= TearDownThread( inMDNS
);
506 err
= TearDownInterfaceList( inMDNS
);
509 err
= TearDownSynchronizationObjects( inMDNS
);
514 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform close done (err=%ld)\n", err
);
517 //===========================================================================================================================
518 // mDNSPlatformSendUDP
519 //===========================================================================================================================
523 const mDNS
* const inMDNS
,
524 const DNSMessage
* const inMsg
,
525 const mDNSu8
* const inMsgEnd
,
526 mDNSInterfaceID inInterfaceID
,
527 mDNSIPPort inSrcPort
,
528 const mDNSAddr
* inDstIP
,
529 mDNSIPPort inDstPort
)
532 mDNSInterfaceData
* ifd
;
533 struct sockaddr_in addr
;
536 MDNS_UNUSED( inSrcPort
);
537 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
544 check( inInterfaceID
);
546 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
548 err
= mStatus_BadParamErr
;
554 ifd
= (mDNSInterfaceData
*) inInterfaceID
;
555 check( IsValidSocket( ifd
->sock
) );
557 addr
.sin_family
= AF_INET
;
558 addr
.sin_port
= inDstPort
.NotAnInteger
;
559 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
561 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
562 n
= sendto( ifd
->sock
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
563 check_errno( n
, errno_compat() );
565 ifd
->sendErrorCounter
+= ( n
< 0 );
566 ifd
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
567 ifd
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
568 err
= mStatus_NoError
;
571 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
575 //===========================================================================================================================
577 //===========================================================================================================================
579 void mDNSPlatformLock( const mDNS
* const inMDNS
)
581 EnterCriticalSection( &inMDNS
->p
->lock
);
584 //===========================================================================================================================
585 // mDNSPlatformUnlock
586 //===========================================================================================================================
588 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
592 check( inMDNS
->p
->lockInitialized
);
593 check( inMDNS
->p
->threadID
);
595 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
596 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
598 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
602 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
605 LeaveCriticalSection( &inMDNS
->p
->lock
);
608 //===========================================================================================================================
609 // mDNSPlatformStrLen
610 //===========================================================================================================================
612 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
616 return( (mDNSu32
) strlen( (const char *) inSrc
) );
619 //===========================================================================================================================
620 // mDNSPlatformStrCopy
621 //===========================================================================================================================
623 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
628 strcpy( (char *) inDst
, (const char*) inSrc
);
631 //===========================================================================================================================
632 // mDNSPlatformMemCopy
633 //===========================================================================================================================
635 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
640 memcpy( inDst
, inSrc
, inSize
);
643 //===========================================================================================================================
644 // mDNSPlatformMemSame
645 //===========================================================================================================================
647 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
652 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
655 //===========================================================================================================================
656 // mDNSPlatformMemZero
657 //===========================================================================================================================
659 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
663 memset( inDst
, 0, inSize
);
666 //===========================================================================================================================
667 // mDNSPlatformMemAllocate
668 //===========================================================================================================================
670 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
676 mem
= malloc( inSize
);
682 //===========================================================================================================================
683 // mDNSPlatformMemFree
684 //===========================================================================================================================
686 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
693 //===========================================================================================================================
694 // mDNSPlatformTimeInit
695 //===========================================================================================================================
697 mDNSexport mStatus
mDNSPlatformTimeInit( mDNSs32
*outTimeNow
)
701 // No special setup is required on Windows -- we just use GetTickCount().
703 *outTimeNow
= mDNSPlatformTimeNow();
704 return( mStatus_NoError
);
707 //===========================================================================================================================
708 // mDNSPlatformTimeNow
709 //===========================================================================================================================
711 mDNSs32
mDNSPlatformTimeNow( void )
713 return( (mDNSs32
) GetTickCount() );
716 //===========================================================================================================================
717 // mDNSPlatformInterfaceNameToID
718 //===========================================================================================================================
720 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
723 mDNSInterfaceData
* ifd
;
729 // Search for an interface with the specified name,
731 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
733 if( strcmp( ifd
->name
, inName
) == 0 )
738 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
744 *outID
= (mDNSInterfaceID
) ifd
;
746 err
= mStatus_NoError
;
752 //===========================================================================================================================
753 // mDNSPlatformInterfaceIDToInfo
754 //===========================================================================================================================
756 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
759 mDNSInterfaceData
* ifd
;
765 // Search for an interface with the specified ID,
767 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
769 if( ifd
== (mDNSInterfaceData
*) inID
)
774 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
778 outInfo
->name
= ifd
->name
;
779 outInfo
->ip
= ifd
->hostSet
.ip
;
780 err
= mStatus_NoError
;
790 //===========================================================================================================================
792 //===========================================================================================================================
794 #if( MDNS_DEBUGMSGS )
795 void debugf_( const char *inFormat
, ... )
801 va_start( args
, inFormat
);
802 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
805 dlog( kDebugLevelInfo
, "%s\n", buffer
);
809 //===========================================================================================================================
811 //===========================================================================================================================
813 #if( MDNS_DEBUGMSGS > 1 )
814 void verbosedebugf_( const char *inFormat
, ... )
820 va_start( args
, inFormat
);
821 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
824 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
828 //===========================================================================================================================
830 //===========================================================================================================================
832 void LogMsg( const char *inFormat
, ... )
838 va_start( args
, inFormat
);
839 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
842 dlog( kDebugLevelWarning
, "%s\n", buffer
);
845 #if( MDNS_DEBUGMSGS )
846 //===========================================================================================================================
847 // mDNSPlatformDebugLog
848 //===========================================================================================================================
850 mDNSlocal
void mDNSPlatformDebugLog( unsigned long inLevel
, const char *inFormat
, ... )
852 if( inLevel
>= gDebugLevel
)
856 va_start( args
, inFormat
);
857 vfprintf( stderr
, inFormat
, args
);
863 //===========================================================================================================================
864 // mDNSPlatformPrintAssert
865 //===========================================================================================================================
868 mDNSPlatformPrintAssert(
869 const char * inSignature
,
871 const char * inAssertionString
,
872 const char * inErrorString
,
873 const char * inFileName
,
874 unsigned long inLineNumber
,
875 const char * inFunction
)
879 char tempSignatureChar
;
883 tempSignatureChar
= '\0';
884 inSignature
= &tempSignatureChar
;
887 dataPtr
+= sprintf( dataPtr
, "\n" );
890 dataPtr
+= sprintf( dataPtr
, "[%s] Error: %ld\n", inSignature
, inError
);
894 dataPtr
+= sprintf( dataPtr
, "[%s] Assertion failed", inSignature
);
895 if( inAssertionString
)
897 dataPtr
+= sprintf( dataPtr
, ": %s", inAssertionString
);
899 dataPtr
+= sprintf( dataPtr
, "\n" );
903 dataPtr
+= sprintf( dataPtr
, "[%s] %s\n", inSignature
, inErrorString
);
907 dataPtr
+= sprintf( dataPtr
, "[%s] file: \"%s\"\n", inSignature
, inFileName
);
911 dataPtr
+= sprintf( dataPtr
, "[%s] line: %ld\n", inSignature
, inLineNumber
);
915 dataPtr
+= sprintf( dataPtr
, "[%s] function: \"%s\"\n", inSignature
, inFunction
);
917 dataPtr
+= sprintf( dataPtr
, "\n" );
918 fprintf( stderr
, "%s", buffer
);
921 #endif // MDNS_DEBUGMSGS
925 #pragma mark == Platform Internals ==
928 //===========================================================================================================================
929 // SetupSynchronizationObjects
930 //===========================================================================================================================
932 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
936 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up synchronization objects\n" );
938 InitializeCriticalSection( &inMDNS
->p
->lock
);
939 inMDNS
->p
->lockInitialized
= mDNStrue
;
941 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
942 require_action( inMDNS
->p
->cancelEvent
, exit
, err
= mStatus_NoMemoryErr
);
944 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
945 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
947 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
948 require_action( inMDNS
->p
->interfaceListChangedEvent
, exit
, err
= mStatus_NoMemoryErr
);
950 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
951 require_action( inMDNS
->p
->wakeupEvent
, exit
, err
= mStatus_NoMemoryErr
);
953 err
= mStatus_NoError
;
958 TearDownSynchronizationObjects( inMDNS
);
960 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up synchronization objects done (err=%ld)\n", err
);
964 //===========================================================================================================================
965 // TearDownSynchronizationObjects
966 //===========================================================================================================================
968 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
972 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down synchronization objects\n" );
974 if( inMDNS
->p
->quitEvent
)
976 CloseHandle( inMDNS
->p
->quitEvent
);
977 inMDNS
->p
->quitEvent
= 0;
979 if( inMDNS
->p
->cancelEvent
)
981 CloseHandle( inMDNS
->p
->cancelEvent
);
982 inMDNS
->p
->cancelEvent
= 0;
984 if( inMDNS
->p
->interfaceListChangedEvent
)
986 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
987 inMDNS
->p
->interfaceListChangedEvent
= 0;
989 if( inMDNS
->p
->wakeupEvent
)
991 CloseHandle( inMDNS
->p
->wakeupEvent
);
992 inMDNS
->p
->wakeupEvent
= 0;
994 if( inMDNS
->p
->lockInitialized
)
996 DeleteCriticalSection( &inMDNS
->p
->lock
);
997 inMDNS
->p
->lockInitialized
= mDNSfalse
;
999 err
= mStatus_NoError
;
1001 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down synchronization objects done (err=%ld)\n", err
);
1005 //===========================================================================================================================
1007 //===========================================================================================================================
1009 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
1012 char tempString
[ 256 ];
1016 // Get the name of this machine.
1018 tempString
[ 0 ] = '\0';
1019 err
= gethostname( tempString
, sizeof( tempString
) - 1 );
1020 check_errno( err
, errno_compat() );
1021 if( err
|| ( tempString
[ 0 ] == '\0' ) )
1023 // Invalidate name so fall back to a default name.
1025 strcpy( tempString
, kMDNSDefaultName
);
1027 tempString
[ sizeof( tempString
) - 1 ] = '\0';
1029 // Set up the host name with mDNS.
1031 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) strlen( tempString
);
1032 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempString
, inMDNS
->nicelabel
.c
[ 0 ] );
1033 ConvertUTF8PstringToRFC1034HostLabel( inMDNS
->nicelabel
.c
, &inMDNS
->hostlabel
);
1034 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
1036 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
1038 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
1040 check( inMDNS
->nicelabel
.c
[ 0 ] != 0 );
1041 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
1043 mDNS_GenerateFQDN( inMDNS
);
1045 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
1046 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
1050 //===========================================================================================================================
1051 // SetupInterfaceList
1052 //===========================================================================================================================
1054 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
1057 mDNSInterfaceData
** next
;
1058 mDNSInterfaceData
* ifd
;
1059 struct ifaddrs
* addrs
;
1064 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list\n" );
1070 // Tear down any existing interfaces that may be set up.
1072 TearDownInterfaceList( inMDNS
);
1074 // Set up the name of this machine.
1076 err
= SetupName( inMDNS
);
1079 // Set up the interface list change notification.
1081 err
= SetupNotifications( inMDNS
);
1084 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
1086 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_LOOPBACK
| IFF_POINTTOPOINT
;
1087 flagTest
= IFF_UP
| IFF_MULTICAST
;
1089 next
= &inMDNS
->p
->interfaceList
;
1091 err
= getifaddrs( &addrs
);
1092 require_noerr( err
, exit
);
1094 for( p
= addrs
; p
; p
= p
->ifa_next
)
1096 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
1098 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) ) // $$$ TO DO: Update for IPv6.
1103 err
= SetupInterface( inMDNS
, (struct sockaddr_in
*) p
->ifa_addr
, &ifd
);
1104 require_noerr( err
, exit
);
1106 strcpy( ifd
->name
, p
->ifa_name
);
1110 ++inMDNS
->p
->interfaceCount
;
1117 TearDownInterfaceList( inMDNS
);
1121 freeifaddrs( addrs
);
1123 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
1127 //===========================================================================================================================
1128 // TearDownInterfaceList
1129 //===========================================================================================================================
1131 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1134 mDNSInterfaceData
* ifd
;
1136 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
1140 // Tear down interface list change notifications.
1142 err
= TearDownNotifications( inMDNS
);
1145 // Tear down all the interfaces.
1147 while( inMDNS
->p
->interfaceList
)
1149 ifd
= inMDNS
->p
->interfaceList
;
1150 inMDNS
->p
->interfaceList
= ifd
->next
;
1152 TearDownInterface( inMDNS
, ifd
);
1154 inMDNS
->p
->interfaceCount
= 0;
1156 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
1157 return( mStatus_NoError
);
1160 //===========================================================================================================================
1162 //===========================================================================================================================
1164 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct sockaddr_in
*inAddress
, mDNSInterfaceData
**outIFD
)
1167 mDNSInterfaceData
* ifd
;
1168 SocketRef socketRef
;
1170 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface\n" );
1176 // Allocate memory for the info item.
1178 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
1179 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
1180 ifd
->sock
= kInvalidSocketRef
;
1182 // Set up a multicast DNS (port 5353) socket for this interface.
1184 err
= SetupSocket( inMDNS
, inAddress
, &socketRef
);
1185 require_noerr( err
, exit
);
1186 ifd
->sock
= socketRef
;
1188 // Set up the read pending event and associate it so we can block until data is available for this socket.
1190 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1191 require_action( ifd
->readPendingEvent
, exit
, err
= mStatus_NoMemoryErr
);
1193 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
1194 require_noerr( err
, exit
);
1196 // Register this interface with mDNS.
1198 ifd
->hostSet
.InterfaceID
= (mDNSInterfaceID
) ifd
;
1199 ifd
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
1200 ifd
->hostSet
.ip
.ip
.v4
.NotAnInteger
= inAddress
->sin_addr
.s_addr
;
1201 ifd
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1203 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->hostSet
);
1204 require_noerr( err
, exit
);
1205 ifd
->hostRegistered
= mDNStrue
;
1207 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1208 ifd
->hostSet
.ip
.ip
.v4
.b
[ 0 ],
1209 ifd
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1210 ifd
->hostSet
.ip
.ip
.v4
.b
[ 2 ],
1211 ifd
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1221 TearDownInterface( inMDNS
, ifd
);
1223 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (err=%ld)\n", err
);
1227 //===========================================================================================================================
1228 // TearDownInterface
1229 //===========================================================================================================================
1231 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
1233 SocketRef socketRef
;
1238 // Deregister this interface with mDNS.
1240 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1241 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 0 ],
1242 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1243 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 2 ],
1244 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1246 if( inIFD
->hostRegistered
)
1248 inIFD
->hostRegistered
= mDNSfalse
;
1249 mDNS_DeregisterInterface( inMDNS
, &inIFD
->hostSet
);
1252 // Tear down the multicast socket.
1254 if( inIFD
->readPendingEvent
)
1256 CloseHandle( inIFD
->readPendingEvent
);
1257 inIFD
->readPendingEvent
= 0;
1260 socketRef
= inIFD
->sock
;
1261 inIFD
->sock
= kInvalidSocketRef
;
1262 if( IsValidSocket( socketRef
) )
1264 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down socket %d\n", socketRef
);
1265 close_compat( socketRef
);
1268 // Free the memory used by the interface info.
1271 return( mStatus_NoError
);
1274 //===========================================================================================================================
1276 //===========================================================================================================================
1280 mDNS
* const inMDNS
,
1281 const struct sockaddr_in
* inAddress
,
1282 SocketRef
* outSocketRef
)
1285 SocketRef socketRef
;
1287 struct ip_mreq mreq
;
1288 struct sockaddr_in addr
;
1291 MDNS_UNUSED( inMDNS
);
1293 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1295 check( outSocketRef
);
1297 // Set up a UDP socket.
1299 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1300 require_action( IsValidSocket( socketRef
), exit
, err
= mStatus_NoMemoryErr
);
1302 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets.
1305 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1306 check_errno( err
, errno_compat() );
1308 // Bind to the mutlicast DNS port 5353.
1310 ip
.NotAnInteger
= inAddress
->sin_addr
.s_addr
;
1311 memset( &addr
, 0, sizeof( addr
) );
1312 addr
.sin_family
= AF_INET
;
1313 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
1314 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1315 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1316 check_errno( err
, errno_compat() );
1318 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1320 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
1321 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1322 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1323 check_errno( err
, errno_compat() );
1325 // Direct multicast packets to the specified interface.
1327 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1328 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1329 check_errno( err
, errno_compat() );
1331 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1334 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1335 check_errno( err
, errno_compat() );
1337 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1340 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
1341 check_errno( err
, errno_compat() );
1345 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%u.%u.%u.%u, %d)\n",
1346 ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], socketRef
);
1348 *outSocketRef
= socketRef
;
1349 socketRef
= kInvalidSocketRef
;
1350 err
= mStatus_NoError
;
1353 if( IsValidSocket( socketRef
) )
1355 close_compat( socketRef
);
1360 //===========================================================================================================================
1361 // SetupNotifications
1362 //===========================================================================================================================
1364 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
1367 SocketRef socketRef
;
1368 unsigned long param
;
1373 // Register to listen for address list changes.
1375 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1376 require_action( IsValidSocket( socketRef
), exit
, err
= mStatus_NoMemoryErr
);
1377 inMDNS
->p
->interfaceListChangedSocketRef
= socketRef
;
1379 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1380 // when a change to the interface list is detected.
1383 err
= ioctlsocket( socketRef
, FIONBIO
, ¶m
);
1384 require_errno( err
, errno_compat(), exit
);
1388 err
= WSAIoctl( socketRef
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1391 check( errno_compat() == WSAEWOULDBLOCK
);
1394 err
= WSAEventSelect( socketRef
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
1395 require_errno( err
, errno_compat(), exit
);
1400 TearDownNotifications( inMDNS
);
1405 //===========================================================================================================================
1406 // TearDownNotifications
1407 //===========================================================================================================================
1409 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
1411 SocketRef socketRef
;
1413 socketRef
= inMDNS
->p
->interfaceListChangedSocketRef
;
1414 inMDNS
->p
->interfaceListChangedSocketRef
= kInvalidSocketRef
;
1415 if( IsValidSocket( socketRef
) )
1417 close_compat( socketRef
);
1419 return( mStatus_NoError
);
1426 //===========================================================================================================================
1428 //===========================================================================================================================
1430 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
1433 HANDLE threadHandle
;
1437 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1439 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
1440 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
1442 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1443 require_action( inMDNS
->p
->initEvent
, exit
, err
= mStatus_NoMemoryErr
);
1444 inMDNS
->p
->initStatus
= mStatus_Invalid
;
1446 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1447 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1449 threadHandle
= (HANDLE
) _beginthreadex( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
1450 require_action( threadHandle
, exit
, err
= mStatus_NoMemoryErr
);
1452 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
1453 require_action( result
== WAIT_OBJECT_0
, exit
, err
= mStatus_UnknownErr
);
1454 err
= inMDNS
->p
->initStatus
;
1455 require_noerr( err
, exit
);
1458 if( inMDNS
->p
->initEvent
)
1460 CloseHandle( inMDNS
->p
->initEvent
);
1461 inMDNS
->p
->initEvent
= 0;
1463 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld)\n", err
);
1467 //===========================================================================================================================
1469 //===========================================================================================================================
1471 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
1475 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
1476 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
1478 if( inMDNS
->p
->cancelEvent
)
1482 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
1485 if( inMDNS
->p
->quitEvent
)
1487 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
1488 check( result
== WAIT_OBJECT_0
);
1491 return( mStatus_NoError
);
1494 //===========================================================================================================================
1496 //===========================================================================================================================
1498 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
1510 m
= (mDNS
*) inParam
;
1511 err
= ProcessingThreadInitialize( m
);
1512 require_noerr( err
, exit
);
1517 // Set up the list of objects we'll be waiting on.
1521 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
1522 require_noerr( err
, exit
);
1524 // Main processing loop.
1528 // Give the mDNS core a chance to do its work and determine next event time.
1530 mDNSs32 interval
= mDNS_Execute(m
) - mDNSPlatformTimeNow();
1531 if (interval
< 0) interval
= 0;
1532 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
1533 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
1535 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1537 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
1538 if( result
== WAIT_TIMEOUT
)
1540 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1542 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
1545 else if( result
== kWaitListCancelEvent
)
1547 // Cancel event. Set the done flag and break to exit.
1549 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
1553 else if( result
== kWaitListInterfaceListChangedEvent
)
1555 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1557 ProcessingThreadInterfaceListChanged( m
);
1560 else if( result
== kWaitListWakeupEvent
)
1562 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
1564 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup\n" );
1571 // Socket data available event. Determine which socket and process the packet.
1573 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
1574 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
1575 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
1576 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
1578 HANDLE signaledObject
;
1580 mDNSInterfaceData
* ifd
;
1582 signaledObject
= waitList
[ waitItemIndex
];
1585 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1587 if( ifd
->readPendingEvent
== signaledObject
)
1589 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
1597 // Unexpected wait result.
1599 dlog( kDebugLevelAllowedError
, DEBUG_NAME
"unexpected wait result (result=0x%08X)\n", result
);
1604 // Release the wait list.
1614 // Signal the quit event to indicate that the thread is finished.
1617 wasSet
= SetEvent( m
->p
->quitEvent
);
1620 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
1621 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1627 //===========================================================================================================================
1628 // ProcessingThreadInitialize
1629 //===========================================================================================================================
1631 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
1636 inMDNS
->p
->threadID
= GetCurrentThreadId();
1638 err
= SetupInterfaceList( inMDNS
);
1639 require_noerr( err
, exit
);
1644 TearDownInterfaceList( inMDNS
);
1646 inMDNS
->p
->initStatus
= err
;
1647 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
1653 //===========================================================================================================================
1654 // ProcessingThreadSetupWaitList
1655 //===========================================================================================================================
1657 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
1662 HANDLE
* waitItemPtr
;
1663 mDNSInterfaceData
* ifd
;
1665 dlog( kDebugLevelVerbose
, DEBUG_NAME
"thread setting up wait list\n" );
1668 check( outWaitList
);
1669 check( outWaitListCount
);
1671 // Allocate an array to hold all the objects to wait on.
1673 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->interfaceCount
;
1674 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
1675 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
1676 waitItemPtr
= waitList
;
1678 // Add the fixed wait items to the beginning of the list.
1680 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
1681 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
1682 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
1684 // Append all the dynamic wait items to the list.
1686 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1688 *waitItemPtr
++ = ifd
->readPendingEvent
;
1691 *outWaitList
= waitList
;
1692 *outWaitListCount
= waitListCount
;
1694 err
= mStatus_NoError
;
1701 dlog( kDebugLevelVerbose
, DEBUG_NAME
"thread setting up wait list done (err=%ld)\n", err
);
1705 //===========================================================================================================================
1706 // ProcessingThreadProcessPacket
1707 //===========================================================================================================================
1709 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSocketRef
)
1713 struct sockaddr_in addr
;
1715 mDNSu8
* packetEndPtr
;
1721 // Receive the packet.
1723 addrSize
= sizeof( addr
);
1724 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1728 // Set up the src/dst/interface info.
1730 srcAddr
.type
= mDNSAddrType_IPv4
;
1731 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1732 srcPort
.NotAnInteger
= addr
.sin_port
;
1733 dstAddr
.type
= mDNSAddrType_IPv4
;
1734 dstAddr
.ip
.v4
= AllDNSLinkGroup
;
1735 dstPort
= MulticastDNSPort
;
1737 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1738 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1739 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%u\n",
1740 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1741 ntohs( srcPort
.NotAnInteger
) );
1742 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%u\n",
1743 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1744 ntohs( dstPort
.NotAnInteger
) );
1745 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %u.%u.%u.%u\n",
1746 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inIFD
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1747 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inIFD
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1749 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1751 // Dispatch the packet to mDNS.
1753 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1754 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inIFD
->hostSet
.InterfaceID
, 255 );
1759 inIFD
->recvCounter
+= 1;
1760 inIFD
->recvErrorCounter
+= ( n
< 0 );
1763 //===========================================================================================================================
1764 // ProcessingThreadInterfaceListChanged
1765 //===========================================================================================================================
1767 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
1771 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed event\n" );
1774 mDNSPlatformLock( inMDNS
);
1776 // Tear down the existing interfaces and set up new ones using the new IP info.
1778 err
= TearDownInterfaceList( inMDNS
);
1781 err
= SetupInterfaceList( inMDNS
);
1784 mDNSPlatformUnlock( inMDNS
);
1786 // Inform clients of the change.
1788 if( inMDNS
->MainCallback
)
1790 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1793 // Force mDNS to update.
1795 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
1800 #pragma mark == Utilities ==
1803 #if( defined( _WIN32_WCE ) )
1804 //===========================================================================================================================
1806 //===========================================================================================================================
1808 int getifaddrs( struct ifaddrs
**outAddrs
)
1814 SOCKET_ADDRESS_LIST
* addressList
;
1815 struct ifaddrs
* head
;
1816 struct ifaddrs
** next
;
1817 struct ifaddrs
* ifa
;
1821 sock
= kInvalidSocketRef
;
1826 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
1828 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1829 require_action( IsValidSocket( sock
), exit
, err
= mStatus_NoMemoryErr
);
1831 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
1832 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
1834 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
1837 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
1838 require_action( size
> 0, exit
, err
= -1 );
1841 buffer
= calloc( 1, size
);
1842 require_action( buffer
, exit
, err
= -1 );
1844 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
1846 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
1847 require_noerr( err
, exit
);
1848 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
1850 // Process the raw interface list and build a linked list of interfaces.
1852 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
1854 n
= addressList
->iAddressCount
;
1859 for( i
= 0; i
< n
; ++i
)
1861 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1862 require_action( ifa
, exit
, err
= WSAENOBUFS
);
1865 next
= &ifa
->ifa_next
;
1867 // Fetch the name. $$$ TO DO: Get the real name of the interface.
1869 ifa
->ifa_name
= (char *) malloc( 16 );
1870 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
1871 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
1873 // Fetch flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
1875 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
1879 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
1883 struct sockaddr_in
* sinptr4
;
1885 sinptr4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
1886 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
1887 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
1888 memcpy( ifa
->ifa_addr
, sinptr4
, sizeof( *sinptr4
) );
1909 freeifaddrs( head
);
1915 if( sock
!= INVALID_SOCKET
)
1917 closesocket( sock
);
1921 #endif // defined( _WIN32_WCE ) )
1923 #if( !defined( _WIN32_WCE ) )
1924 //===========================================================================================================================
1926 //===========================================================================================================================
1928 int getifaddrs( struct ifaddrs
**outAddrs
)
1934 INTERFACE_INFO
* buffer
;
1935 INTERFACE_INFO
* tempBuffer
;
1936 INTERFACE_INFO
* ifInfo
;
1939 struct ifaddrs
* head
;
1940 struct ifaddrs
** next
;
1941 struct ifaddrs
* ifa
;
1942 struct sockaddr_in
* sinptr4
;
1943 struct sockaddr_in6_old
* sinptr6
;
1944 struct sockaddr
* sa
;
1946 sock
= INVALID_SOCKET
;
1951 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
1952 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
1953 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
1955 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1956 require_action( sock
!= INVALID_SOCKET
, exit
, err
= WSAEMFILE
);
1959 size
= 16 * sizeof( INTERFACE_INFO
);
1962 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
1963 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
1964 buffer
= tempBuffer
;
1966 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
1973 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
1975 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
1977 check( actualSize
<= size
);
1978 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
1979 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
1981 // Process the raw interface list and build a linked list of interfaces.
1983 for( i
= 0; i
< n
; ++i
)
1985 ifInfo
= &buffer
[ i
];
1987 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1988 require_action( ifa
, exit
, err
= WSAENOBUFS
);
1991 next
= &ifa
->ifa_next
;
1993 // Fetch the name. $$$ TO DO: Get the real name of the interface.
1995 ifa
->ifa_name
= (char *) malloc( 16 );
1996 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
1997 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
1999 // Fetch interface flags.
2001 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
2005 switch( ifInfo
->iiAddress
.Address
.sa_family
)
2008 sinptr4
= &ifInfo
->iiAddress
.AddressIn
;
2009 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
2010 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
2011 memcpy( ifa
->ifa_addr
, sinptr4
, sizeof( *sinptr4
) );
2013 if( ifInfo
->iiNetmask
.Address
.sa_family
== AF_INET
)
2015 sinptr4
= &ifInfo
->iiNetmask
.AddressIn
;
2016 ifa
->ifa_netmask
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
2017 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
2018 memcpy( ifa
->ifa_netmask
, sinptr4
, sizeof( *sinptr4
) );
2021 if( ifInfo
->iiBroadcastAddress
.Address
.sa_family
== AF_INET
)
2023 sinptr4
= &ifInfo
->iiBroadcastAddress
.AddressIn
;
2024 ifa
->ifa_broadaddr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
2025 require_action( ifa
->ifa_broadaddr
, exit
, err
= WSAENOBUFS
);
2026 memcpy( ifa
->ifa_broadaddr
, sinptr4
, sizeof( *sinptr4
) );
2031 sinptr6
= &ifInfo
->iiAddress
.AddressIn6
;
2032 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr6
) );
2033 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
2034 memcpy( ifa
->ifa_addr
, sinptr6
, sizeof( *sinptr6
) );
2038 sa
= &ifInfo
->iiAddress
.Address
;
2039 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa
) );
2040 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
2041 memcpy( ifa
->ifa_addr
, sa
, sizeof( *sa
) );
2058 freeifaddrs( head
);
2064 if( sock
!= INVALID_SOCKET
)
2066 closesocket( sock
);
2070 #endif // !defined( _WIN32_WCE ) )
2072 //===========================================================================================================================
2074 //===========================================================================================================================
2076 void freeifaddrs( struct ifaddrs
*inAddrs
)
2081 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
2083 for( p
= inAddrs
; p
; p
= q
)
2089 free( p
->ifa_name
);
2094 free( p
->ifa_addr
);
2097 if( p
->ifa_netmask
)
2099 free( p
->ifa_netmask
);
2100 p
->ifa_netmask
= NULL
;
2102 if( p
->ifa_broadaddr
)
2104 free( p
->ifa_broadaddr
);
2105 p
->ifa_broadaddr
= NULL
;
2107 if( p
->ifa_dstaddr
)
2109 free( p
->ifa_dstaddr
);
2110 p
->ifa_dstaddr
= NULL
;
2114 free( p
->ifa_data
);
2121 #if( !defined( _WIN32_WCE ) )
2122 //===========================================================================================================================
2124 //===========================================================================================================================
2126 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
2131 if( inAddrSize
== 0 )
2133 if( inFamily
== AF_INET
)
2135 inAddrSize
= sizeof( struct sockaddr_in
);
2137 else if( inFamily
== AF_INET6
)
2139 inAddrSize
= sizeof( struct sockaddr_in6
);
2143 err
= WSAEAFNOSUPPORT
;
2147 size
= (int) inAddrSize
;
2149 err
= WSAStringToAddressA( (char *) inString
, inFamily
, NULL
, (LPSOCKADDR
) outAddr
, &size
);
2150 if( err
!= 0 ) goto exit
;
2154 *outAddrSize
= (size_t) size
;
2161 //===========================================================================================================================
2163 //===========================================================================================================================
2165 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
2171 if( inAddrSize
== 0 )
2173 const struct sockaddr
* addr
;
2175 addr
= (const struct sockaddr
*) inAddr
;
2176 if( addr
->sa_family
== AF_INET
)
2178 size
= sizeof( struct sockaddr_in
);
2180 else if( addr
->sa_family
== AF_INET6
)
2182 size
= sizeof( struct sockaddr_in6
);
2186 WSASetLastError( WSAEAFNOSUPPORT
);
2193 size
= (DWORD
) inAddrSize
;
2196 stringSize
= (DWORD
) inBufferSize
;
2197 err
= WSAAddressToStringA( (LPSOCKADDR
) inAddr
, size
, NULL
, inBuffer
, &stringSize
);
2206 #endif // !defined( _WIN32_WCE )