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 2003/08/20 06:21:25 bradley
27 Updated to latest internal version of the Rendezvous for Windows platform plugin: Added support
28 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
29 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
30 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
31 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
32 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
33 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
34 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
35 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
37 Revision 1.21 2003/08/18 23:09:57 cheshire
38 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
40 Revision 1.20 2003/08/12 19:56:27 cheshire
43 Revision 1.19 2003/08/05 23:58:18 cheshire
44 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
45 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
47 Revision 1.18 2003/07/23 21:16:30 cheshire
48 Removed a couple of debugfs
50 Revision 1.17 2003/07/23 02:23:01 cheshire
51 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
52 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
54 Revision 1.16 2003/07/19 03:15:16 cheshire
55 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
56 and add the obvious trivial implementations to each platform support layer
58 Revision 1.15 2003/07/02 21:20:04 cheshire
59 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
61 Revision 1.14 2003/05/26 03:21:30 cheshire
62 Tidy up address structure naming:
63 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
64 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
65 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
67 Revision 1.13 2003/05/26 03:01:28 cheshire
68 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
70 Revision 1.12 2003/05/06 21:06:05 cheshire
71 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
73 Revision 1.11 2003/05/06 00:00:51 cheshire
74 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
76 Revision 1.10 2003/04/29 00:06:09 cheshire
77 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
79 Revision 1.9 2003/04/26 02:40:01 cheshire
80 Add void LogMsg( const char *format, ... )
82 Revision 1.8 2003/03/22 02:57:44 cheshire
83 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
85 Revision 1.7 2003/03/15 04:40:38 cheshire
86 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
88 Revision 1.6 2003/02/21 01:54:10 cheshire
89 Bug #: 3099194 mDNSResponder needs performance improvements
90 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
92 Revision 1.5 2003/02/20 00:59:03 cheshire
93 Brought Windows code up to date so it complies with
94 Josh Graessley's interface changes for IPv6 support.
95 (Actual support for IPv6 on Windows will come later.)
97 Revision 1.4 2002/09/21 20:44:54 zarzycki
100 Revision 1.3 2002/09/20 05:50:45 bradley
101 Multicast DNS platform plugin for Win32
105 #if( defined( _MSC_VER ) )
106 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
109 #if( !defined( WIN32_LEAN_AND_MEAN ) )
110 #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
120 #include <winsock2.h>
121 #include <Ws2tcpip.h>
123 #if( !defined( _WIN32_WCE ) ) // Windows CE does not have process.h.
131 #include "mDNSClientAPI.h"
132 #include "mDNSPlatformFunctions.h"
134 #include "mDNSWin32.h"
137 #pragma mark == Constants ==
140 //===========================================================================================================================
142 //===========================================================================================================================
144 #define DEBUG_NAME "[mDNS] "
146 #if( !defined( MDNS_DEBUG_SIGNATURE ) )
147 #define MDNS_DEBUG_SIGNATURE "mDNS"
150 #define kMDNSDefaultName "My Computer"
152 #define kWinSockMajorMin 2
153 #define kWinSockMinorMin 2
155 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
156 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
157 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
158 #define kWaitListFixedItemCount 3
161 #pragma mark == Macros - Debug ==
164 //===========================================================================================================================
166 //===========================================================================================================================
168 #define MDNS_UNUSED( X ) (void)( X )
170 #define kDebugLevelMask 0x0000FFFFL
171 #define kDebugLevelChatty 100L
172 #define kDebugLevelVerbose 500L
173 #define kDebugLevelTrace 800L
174 #define kDebugLevelInfo 1000L
175 #define kDebugLevelRareInfo 2000L
176 #define kDebugLevelNotice 3000L
177 #define kDebugLevelWarning 4000L
178 #define kDebugLevelAllowedError 5000L
179 #define kDebugLevelAssert 6000L
180 #define kDebugLevelRequire 7000L
181 #define kDebugLevelError 8000L
182 #define kDebugLevelCritical 9000L
183 #define kDebugLevelCriticalError kDebugLevelCritical // DEPRECATED
184 #define kDebugLevelAlert 10000L
185 #define kDebugLevelEmergency 11000L
186 #define kDebugLevelTragic 12000L
187 #define kDebugLevelAny 0x0000FFFFL
189 #if( defined( __MWERKS__ ) || defined( __GNUC__ ) )
190 #define __ROUTINE__ __FUNCTION__
192 // Apple and Symantec compilers don't support the C99/GCC extensions yet.
194 #define __ROUTINE__ NULL
197 #if( MDNS_DEBUGMSGS )
198 #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION ) \
199 mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, 0, ( ASSERT_STRING ), NULL, ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
201 #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION ) \
202 mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, ( ERR ), ( ASSERT_STRING ), ( ERROR_STRING ), \
203 ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
205 #define dlog mDNSPlatformDebugLog
207 #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION )
209 #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION )
211 #define dlog while( 0 )
215 /// The following debugging macros emulate those available on Mac OS in AssertMacros.h/Debugging.h.
223 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
227 #define check_noerr( ERR ) \
229 if( ( ERR ) != 0 ) { \
230 debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
234 #define check_errno( ERR, ERRNO ) \
238 localErr = (int)( ERR ); \
239 if( localErr < 0 ) { \
242 localErrno = ( ERRNO ); \
243 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
244 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
250 #define require( X, LABEL ) \
253 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
258 #define require_quiet( X, LABEL ) \
265 #define require_action( X, LABEL, ACTION ) \
268 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
274 #define require_action_quiet( X, LABEL, ACTION ) \
282 #define require_noerr( ERR, LABEL ) \
284 if( ( ERR ) != 0 ) { \
285 debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
290 #define require_noerr_quiet( ERR, LABEL ) \
292 if( ( ERR ) != 0 ) { \
297 #define require_errno( ERR, ERRNO, LABEL ) \
301 localErr = (int)( ERR ); \
302 if( localErr < 0 ) { \
305 localErrno = ( ERRNO ); \
306 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
307 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
312 #define require_errno_action( ERR, ERRNO, LABEL, ACTION ) \
316 localErr = (int)( ERR ); \
317 if( localErr < 0 ) { \
320 localErrno = ( ERRNO ); \
321 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
322 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
329 #pragma mark == Macros - General ==
332 //===========================================================================================================================
334 //===========================================================================================================================
336 #define kInvalidSocketRef INVALID_SOCKET
337 #define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
338 #define close_compat( X ) closesocket( X )
339 #define errno_compat() WSAGetLastError()
341 // _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking
342 // resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to
343 // CreateThread on Windows CE.
345 #if( defined( _WIN32_WCE ) )
346 #define _beginthreadex( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR ) \
347 CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS, \
348 (LPDWORD) THREAD_ID_PTR )
350 #define _endthreadex( RESULT )
354 #pragma mark == Prototypes ==
357 //===========================================================================================================================
359 //===========================================================================================================================
361 #if( MDNS_DEBUGMSGS )
362 mDNSlocal
void mDNSPlatformDebugLog( unsigned long inLevel
, const char *inFormat
, ... );
364 mDNSPlatformPrintAssert(
365 const char * inSignature
,
367 const char * inAssertionString
,
368 const char * inErrorString
,
369 const char * inFileName
,
370 unsigned long inLineNumber
,
371 const char * inFunction
);
374 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
375 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
376 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
377 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
378 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
379 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct sockaddr_in
*inAddress
, mDNSInterfaceData
**outIFD
);
380 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
381 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
,
382 const struct sockaddr_in
* inAddress
,
384 SocketRef
* outSocketRef
);
385 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
386 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
388 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
389 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
390 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
391 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
392 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
393 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSocketRef
);
394 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
396 // Platform Accessors
402 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
403 struct mDNSPlatformInterfaceInfo
409 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
410 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
417 #pragma mark == Globals ==
420 //===========================================================================================================================
422 //===========================================================================================================================
424 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
425 mDNSs32 mDNSPlatformOneSecond
= 0;
427 #if( MDNS_DEBUGMSGS )
428 mDNSlocal
unsigned long gDebugLevel
= kDebugLevelInfo
+ 1;
433 #pragma mark == Platform Support APIs ==
436 //===========================================================================================================================
438 //===========================================================================================================================
440 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
446 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform init\n" );
448 // Initialize variables.
450 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
451 inMDNS
->p
= &gMDNSPlatformSupport
;
452 inMDNS
->p
->interfaceListChangedSocketRef
= kInvalidSocketRef
;
453 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time.
455 // Set everything up.
457 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
458 require_noerr( err
, exit
);
460 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
461 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
463 err
= SetupSynchronizationObjects( inMDNS
);
464 require_noerr( err
, exit
);
466 err
= SetupThread( inMDNS
);
467 require_noerr( err
, exit
);
471 mDNSCoreInitComplete( inMDNS
, err
);
476 mDNSPlatformClose( inMDNS
);
478 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform init done (err=%ld)\n", err
);
482 //===========================================================================================================================
484 //===========================================================================================================================
486 void mDNSPlatformClose( mDNS
* const inMDNS
)
490 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform close\n" );
493 // Tear everything down in reverse order to how it was set up.
495 err
= TearDownThread( inMDNS
);
498 err
= TearDownInterfaceList( inMDNS
);
501 err
= TearDownSynchronizationObjects( inMDNS
);
506 dlog( kDebugLevelVerbose
, DEBUG_NAME
"platform close done (err=%ld)\n", err
);
509 //===========================================================================================================================
510 // mDNSPlatformSendUDP
511 //===========================================================================================================================
515 const mDNS
* const inMDNS
,
516 const DNSMessage
* const inMsg
,
517 const mDNSu8
* const inMsgEnd
,
518 mDNSInterfaceID inInterfaceID
,
519 mDNSIPPort inSrcPort
,
520 const mDNSAddr
* inDstIP
,
521 mDNSIPPort inDstPort
)
524 mDNSInterfaceData
* ifd
;
525 struct sockaddr_in addr
;
528 MDNS_UNUSED( inSrcPort
);
529 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP\n" );
536 check( inInterfaceID
);
538 if( inDstIP
->type
!= mDNSAddrType_IPv4
)
540 err
= mStatus_BadParamErr
;
546 ifd
= (mDNSInterfaceData
*) inInterfaceID
;
547 check( IsValidSocket( ifd
->multicastSocketRef
) );
549 addr
.sin_family
= AF_INET
;
550 addr
.sin_port
= inDstPort
.NotAnInteger
;
551 addr
.sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
553 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
554 n
= sendto( ifd
->multicastSocketRef
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
555 check_errno( n
, errno_compat() );
557 ifd
->sendErrorCounter
+= ( n
< 0 );
558 ifd
->sendMulticastCounter
+= ( inDstPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
559 ifd
->sendUnicastCounter
+= ( inDstPort
.NotAnInteger
!= MulticastDNSPort
.NotAnInteger
);
560 err
= mStatus_NoError
;
563 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send UDP done\n" );
567 //===========================================================================================================================
569 //===========================================================================================================================
571 void mDNSPlatformLock( const mDNS
* const inMDNS
)
573 EnterCriticalSection( &inMDNS
->p
->lock
);
576 //===========================================================================================================================
577 // mDNSPlatformUnlock
578 //===========================================================================================================================
580 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
584 check( inMDNS
->p
->threadID
);
586 // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
587 // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
588 // (a) handle immediate work (if any) resulting from this API call
589 // (b) calculate the next sleep time between now and the next interesting event
591 if( ( mDNSPlatformTimeNow() - inMDNS
->NextScheduledEvent
) >= 0 )
593 // We only need to case a wakeup event when called from a task other than the mDNS task since if we are
594 // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
596 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
600 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
604 LeaveCriticalSection( &inMDNS
->p
->lock
);
607 //===========================================================================================================================
608 // mDNSPlatformStrLen
609 //===========================================================================================================================
611 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
615 return( (mDNSu32
) strlen( (const char *) inSrc
) );
618 //===========================================================================================================================
619 // mDNSPlatformStrCopy
620 //===========================================================================================================================
622 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
627 strcpy( (char *) inDst
, (const char*) inSrc
);
630 //===========================================================================================================================
631 // mDNSPlatformMemCopy
632 //===========================================================================================================================
634 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
639 memcpy( inDst
, inSrc
, inSize
);
642 //===========================================================================================================================
643 // mDNSPlatformMemSame
644 //===========================================================================================================================
646 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
651 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
654 //===========================================================================================================================
655 // mDNSPlatformMemZero
656 //===========================================================================================================================
658 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
662 memset( inDst
, 0, inSize
);
665 //===========================================================================================================================
666 // mDNSPlatformMemAllocate
667 //===========================================================================================================================
669 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
675 mem
= malloc( inSize
);
681 //===========================================================================================================================
682 // mDNSPlatformMemFree
683 //===========================================================================================================================
685 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
692 //===========================================================================================================================
693 // mDNSPlatformTimeInit
694 //===========================================================================================================================
696 mDNSexport mStatus
mDNSPlatformTimeInit( mDNSs32
*outTimeNow
)
700 // No special setup is required on Windows -- we just use GetTickCount().
702 *outTimeNow
= mDNSPlatformTimeNow();
703 return( mStatus_NoError
);
706 //===========================================================================================================================
707 // mDNSPlatformTimeNow
708 //===========================================================================================================================
710 mDNSs32
mDNSPlatformTimeNow( void )
712 return( (mDNSs32
) GetTickCount() );
715 //===========================================================================================================================
716 // mDNSPlatformInterfaceNameToID
717 //===========================================================================================================================
719 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
722 mDNSInterfaceData
* ifd
;
728 // Search for an interface with the specified name,
730 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
732 if( strcmp( ifd
->name
, inName
) == 0 )
737 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
743 *outID
= (mDNSInterfaceID
) ifd
;
745 err
= mStatus_NoError
;
751 //===========================================================================================================================
752 // mDNSPlatformInterfaceIDToInfo
753 //===========================================================================================================================
755 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
758 mDNSInterfaceData
* ifd
;
764 // Search for an interface with the specified ID,
766 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
768 if( ifd
== (mDNSInterfaceData
*) inID
)
773 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
777 outInfo
->name
= ifd
->name
;
778 outInfo
->ip
= ifd
->hostSet
.ip
;
779 err
= mStatus_NoError
;
789 //===========================================================================================================================
791 //===========================================================================================================================
793 #if( MDNS_DEBUGMSGS )
794 void debugf_( const char *inFormat
, ... )
800 va_start( args
, inFormat
);
801 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
804 dlog( kDebugLevelInfo
, "%s\n", buffer
);
808 //===========================================================================================================================
810 //===========================================================================================================================
812 #if( MDNS_DEBUGMSGS > 1 )
813 void verbosedebugf_( const char *inFormat
, ... )
819 va_start( args
, inFormat
);
820 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
823 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
827 //===========================================================================================================================
829 //===========================================================================================================================
831 void LogMsg( const char *inFormat
, ... )
837 va_start( args
, inFormat
);
838 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
841 dlog( kDebugLevelWarning
, "%s\n", buffer
);
844 #if( MDNS_DEBUGMSGS )
845 //===========================================================================================================================
846 // mDNSPlatformDebugLog
847 //===========================================================================================================================
849 mDNSlocal
void mDNSPlatformDebugLog( unsigned long inLevel
, const char *inFormat
, ... )
851 if( inLevel
>= gDebugLevel
)
855 va_start( args
, inFormat
);
856 vfprintf( stderr
, inFormat
, args
);
862 //===========================================================================================================================
863 // mDNSPlatformPrintAssert
864 //===========================================================================================================================
867 mDNSPlatformPrintAssert(
868 const char * inSignature
,
870 const char * inAssertionString
,
871 const char * inErrorString
,
872 const char * inFileName
,
873 unsigned long inLineNumber
,
874 const char * inFunction
)
878 char tempSignatureChar
;
882 tempSignatureChar
= '\0';
883 inSignature
= &tempSignatureChar
;
886 dataPtr
+= sprintf( dataPtr
, "\n" );
889 dataPtr
+= sprintf( dataPtr
, "[%s] Error: %ld\n", inSignature
, inError
);
893 dataPtr
+= sprintf( dataPtr
, "[%s] Assertion failed", inSignature
);
894 if( inAssertionString
)
896 dataPtr
+= sprintf( dataPtr
, ": %s", inAssertionString
);
898 dataPtr
+= sprintf( dataPtr
, "\n" );
902 dataPtr
+= sprintf( dataPtr
, "[%s] %s\n", inSignature
, inErrorString
);
906 dataPtr
+= sprintf( dataPtr
, "[%s] file: \"%s\"\n", inSignature
, inFileName
);
910 dataPtr
+= sprintf( dataPtr
, "[%s] line: %ld\n", inSignature
, inLineNumber
);
914 dataPtr
+= sprintf( dataPtr
, "[%s] function: \"%s\"\n", inSignature
, inFunction
);
916 dataPtr
+= sprintf( dataPtr
, "\n" );
917 fprintf( stderr
, "%s", buffer
);
920 #endif // MDNS_DEBUGMSGS
924 #pragma mark == Platform Internals ==
927 //===========================================================================================================================
928 // SetupSynchronizationObjects
929 //===========================================================================================================================
931 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
935 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up synchronization objects\n" );
937 InitializeCriticalSection( &inMDNS
->p
->lock
);
938 inMDNS
->p
->lockInitialized
= mDNStrue
;
940 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
941 require_action( inMDNS
->p
->cancelEvent
, exit
, err
= mStatus_NoMemoryErr
);
943 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
944 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
946 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
947 require_action( inMDNS
->p
->interfaceListChangedEvent
, exit
, err
= mStatus_NoMemoryErr
);
949 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
950 require_action( inMDNS
->p
->wakeupEvent
, exit
, err
= mStatus_NoMemoryErr
);
952 err
= mStatus_NoError
;
957 TearDownSynchronizationObjects( inMDNS
);
959 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up synchronization objects done (err=%ld)\n", err
);
963 //===========================================================================================================================
964 // TearDownSynchronizationObjects
965 //===========================================================================================================================
967 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
971 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down synchronization objects\n" );
973 if( inMDNS
->p
->quitEvent
)
975 CloseHandle( inMDNS
->p
->quitEvent
);
976 inMDNS
->p
->quitEvent
= 0;
978 if( inMDNS
->p
->cancelEvent
)
980 CloseHandle( inMDNS
->p
->cancelEvent
);
981 inMDNS
->p
->cancelEvent
= 0;
983 if( inMDNS
->p
->interfaceListChangedEvent
)
985 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
986 inMDNS
->p
->interfaceListChangedEvent
= 0;
988 if( inMDNS
->p
->wakeupEvent
)
990 CloseHandle( inMDNS
->p
->wakeupEvent
);
991 inMDNS
->p
->wakeupEvent
= 0;
993 if( inMDNS
->p
->lockInitialized
)
995 DeleteCriticalSection( &inMDNS
->p
->lock
);
996 inMDNS
->p
->lockInitialized
= mDNSfalse
;
998 err
= mStatus_NoError
;
1000 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down synchronization objects done (err=%ld)\n", err
);
1004 //===========================================================================================================================
1006 //===========================================================================================================================
1008 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
1011 char tempString
[ 256 ];
1015 // Get the name of this machine.
1017 tempString
[ 0 ] = '\0';
1018 err
= gethostname( tempString
, sizeof( tempString
) - 1 );
1019 check_errno( err
, errno_compat() );
1020 if( err
|| ( tempString
[ 0 ] == '\0' ) )
1022 // Invalidate name so fall back to a default name.
1024 strcpy( tempString
, kMDNSDefaultName
);
1026 tempString
[ sizeof( tempString
) - 1 ] = '\0';
1028 // Set up the host name with mDNS.
1030 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) strlen( tempString
);
1031 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempString
, inMDNS
->nicelabel
.c
[ 0 ] );
1032 ConvertUTF8PstringToRFC1034HostLabel( inMDNS
->nicelabel
.c
, &inMDNS
->hostlabel
);
1033 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
1035 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
1037 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
1039 check( inMDNS
->nicelabel
.c
[ 0 ] != 0 );
1040 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
1042 mDNS_GenerateFQDN( inMDNS
);
1044 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
1045 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
1049 //===========================================================================================================================
1050 // SetupInterfaceList
1051 //===========================================================================================================================
1053 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
1056 mDNSInterfaceData
** next
;
1057 mDNSInterfaceData
* ifd
;
1058 struct ifaddrs
* addrs
;
1060 struct ifaddrs
* loopback
;
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
;
1090 next
= &inMDNS
->p
->interfaceList
;
1092 err
= getifaddrs( &addrs
);
1093 require_noerr( err
, exit
);
1095 for( p
= addrs
; p
; p
= p
->ifa_next
)
1097 if( ( p
->ifa_flags
& flagMask
) == flagTest
)
1099 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) ) // $$$ TO DO: Update for IPv6.
1104 err
= SetupInterface( inMDNS
, (struct sockaddr_in
*) p
->ifa_addr
, &ifd
);
1105 require_noerr( err
, exit
);
1107 strcpy( ifd
->name
, p
->ifa_name
);
1111 ++inMDNS
->p
->interfaceCount
;
1118 TearDownInterfaceList( inMDNS
);
1122 freeifaddrs( addrs
);
1124 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface list done (err=%ld)\n", err
);
1128 //===========================================================================================================================
1129 // TearDownInterfaceList
1130 //===========================================================================================================================
1132 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1135 mDNSInterfaceData
* ifd
;
1137 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list\n" );
1141 // Tear down interface list change notifications.
1143 err
= TearDownNotifications( inMDNS
);
1146 // Tear down all the interfaces.
1148 while( inMDNS
->p
->interfaceList
)
1150 ifd
= inMDNS
->p
->interfaceList
;
1151 inMDNS
->p
->interfaceList
= ifd
->next
;
1153 TearDownInterface( inMDNS
, ifd
);
1155 inMDNS
->p
->interfaceCount
= 0;
1157 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down interface list done\n" );
1158 return( mStatus_NoError
);
1161 //===========================================================================================================================
1163 //===========================================================================================================================
1165 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct sockaddr_in
*inAddress
, mDNSInterfaceData
**outIFD
)
1168 mDNSInterfaceData
* ifd
;
1169 SocketRef socketRef
;
1171 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface\n" );
1177 // Allocate memory for the info item.
1179 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
1180 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
1181 ifd
->multicastSocketRef
= kInvalidSocketRef
;
1182 ifd
->unicastSocketRef
= kInvalidSocketRef
;
1185 /// Set up multicast portion of interface.
1188 // Set up the multicast DNS (port 5353) socket for this interface.
1190 err
= SetupSocket( inMDNS
, inAddress
, MulticastDNSPort
, &socketRef
);
1191 require_noerr( err
, exit
);
1192 ifd
->multicastSocketRef
= socketRef
;
1194 // Set up the read pending event and associate it so we can block until data is available for this socket.
1196 ifd
->multicastReadPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1197 require_action( ifd
->multicastReadPendingEvent
, exit
, err
= mStatus_NoMemoryErr
);
1199 err
= WSAEventSelect( ifd
->multicastSocketRef
, ifd
->multicastReadPendingEvent
, FD_READ
);
1200 require_noerr( err
, exit
);
1203 /// Set up unicast portion of interface.
1206 // Set up the unicast DNS (port 53) socket for this interface (to handle normal DNS requests).
1208 err
= SetupSocket( inMDNS
, inAddress
, UnicastDNSPort
, &socketRef
);
1209 require_noerr( err
, exit
);
1210 ifd
->unicastSocketRef
= socketRef
;
1212 // Set up the read pending event and associate it so we can block until data is available for this socket.
1214 ifd
->unicastReadPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1215 require_action( ifd
->unicastReadPendingEvent
, exit
, err
= mStatus_NoMemoryErr
);
1217 err
= WSAEventSelect( ifd
->unicastSocketRef
, ifd
->unicastReadPendingEvent
, FD_READ
);
1218 require_noerr( err
, exit
);
1220 // Register this interface with mDNS.
1222 ifd
->hostSet
.InterfaceID
= (mDNSInterfaceID
) ifd
;
1223 ifd
->hostSet
.ip
.type
= mDNSAddrType_IPv4
;
1224 ifd
->hostSet
.ip
.ip
.v4
.NotAnInteger
= inAddress
->sin_addr
.s_addr
;
1225 ifd
->hostSet
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1227 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->hostSet
);
1228 require_noerr( err
, exit
);
1229 ifd
->hostRegistered
= mDNStrue
;
1231 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered IP address: %u.%u.%u.%u\n",
1232 ifd
->hostSet
.ip
.ip
.v4
.b
[ 0 ],
1233 ifd
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1234 ifd
->hostSet
.ip
.ip
.v4
.b
[ 2 ],
1235 ifd
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1245 TearDownInterface( inMDNS
, ifd
);
1247 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up interface done (err=%ld)\n", err
);
1251 //===========================================================================================================================
1252 // TearDownInterface
1253 //===========================================================================================================================
1255 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
1257 SocketRef socketRef
;
1262 // Deregister this interface with mDNS.
1264 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering IP address: %u.%u.%u.%u\n",
1265 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 0 ],
1266 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1267 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 2 ],
1268 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1270 if( inIFD
->hostRegistered
)
1272 inIFD
->hostRegistered
= mDNSfalse
;
1273 mDNS_DeregisterInterface( inMDNS
, &inIFD
->hostSet
);
1276 // Tear down the multicast socket.
1278 if( inIFD
->multicastReadPendingEvent
)
1280 CloseHandle( inIFD
->multicastReadPendingEvent
);
1281 inIFD
->multicastReadPendingEvent
= 0;
1284 socketRef
= inIFD
->multicastSocketRef
;
1285 inIFD
->multicastSocketRef
= kInvalidSocketRef
;
1286 if( IsValidSocket( socketRef
) )
1288 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down multicast socket %d\n", socketRef
);
1289 close_compat( socketRef
);
1292 // Tear down the unicast socket.
1294 if( inIFD
->unicastReadPendingEvent
)
1296 CloseHandle( inIFD
->unicastReadPendingEvent
);
1297 inIFD
->unicastReadPendingEvent
= 0;
1300 socketRef
= inIFD
->unicastSocketRef
;
1301 inIFD
->unicastSocketRef
= kInvalidSocketRef
;
1302 if( IsValidSocket( socketRef
) )
1304 dlog( kDebugLevelVerbose
, DEBUG_NAME
"tearing down unicast socket %d\n", socketRef
);
1305 close_compat( socketRef
);
1308 // Free the memory used by the interface info.
1311 return( mStatus_NoError
);
1314 //===========================================================================================================================
1316 //===========================================================================================================================
1320 mDNS
* const inMDNS
,
1321 const struct sockaddr_in
* inAddress
,
1323 SocketRef
* outSocketRef
)
1326 SocketRef socketRef
;
1328 struct ip_mreq mreq
;
1329 struct sockaddr_in addr
;
1332 MDNS_UNUSED( inMDNS
);
1334 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done\n" );
1336 check( outSocketRef
);
1338 // Set up a UDP socket.
1340 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1341 require_action( IsValidSocket( socketRef
), exit
, err
= mStatus_NoMemoryErr
);
1343 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets.
1346 err
= setsockopt( socketRef
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1347 check_errno( err
, errno_compat() );
1349 // Bind to the specified port (53 for unicast or 5353 for multicast).
1351 ip
.NotAnInteger
= inAddress
->sin_addr
.s_addr
;
1352 memset( &addr
, 0, sizeof( addr
) );
1353 addr
.sin_family
= AF_INET
;
1354 addr
.sin_port
= inPort
.NotAnInteger
;
1355 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1356 err
= bind( socketRef
, (struct sockaddr
*) &addr
, sizeof( addr
) );
1357 if( err
&& ( inPort
.NotAnInteger
== UnicastDNSPort
.NotAnInteger
) )
1359 // Some systems prevent code without root permissions from binding to the DNS port so ignore this
1360 // error since it is not critical. This should only occur with non-root processes.
1364 check_errno( err
, errno_compat() );
1366 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1368 if( inPort
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
)
1370 mreq
.imr_multiaddr
.s_addr
= AllDNSLinkGroup
.NotAnInteger
;
1371 mreq
.imr_interface
.s_addr
= ip
.NotAnInteger
;
1372 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreq
, sizeof( mreq
) );
1373 check_errno( err
, errno_compat() );
1376 // Direct multicast packets to the specified interface.
1378 addr
.sin_addr
.s_addr
= ip
.NotAnInteger
;
1379 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addr
.sin_addr
, sizeof( addr
.sin_addr
) );
1380 check_errno( err
, errno_compat() );
1382 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1385 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1386 check_errno( err
, errno_compat() );
1388 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1391 err
= setsockopt( socketRef
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
1392 check_errno( err
, errno_compat() );
1396 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up socket done (%u.%u.%u.%u:%u, %d)\n",
1397 ip
.b
[ 0 ], ip
.b
[ 1 ], ip
.b
[ 2 ], ip
.b
[ 3 ], ntohs( inPort
.NotAnInteger
), socketRef
);
1399 *outSocketRef
= socketRef
;
1400 socketRef
= kInvalidSocketRef
;
1401 err
= mStatus_NoError
;
1404 if( IsValidSocket( socketRef
) )
1406 close_compat( socketRef
);
1411 //===========================================================================================================================
1412 // SetupNotifications
1413 //===========================================================================================================================
1415 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
1418 SocketRef socketRef
;
1419 unsigned long param
;
1424 // Register to listen for address list changes.
1426 socketRef
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1427 require_action( IsValidSocket( socketRef
), exit
, err
= mStatus_NoMemoryErr
);
1428 inMDNS
->p
->interfaceListChangedSocketRef
= socketRef
;
1430 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1431 // when a change to the interface list is detected.
1434 err
= ioctlsocket( socketRef
, FIONBIO
, ¶m
);
1435 require_errno( err
, errno_compat(), exit
);
1439 err
= WSAIoctl( socketRef
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1442 check( errno_compat() == WSAEWOULDBLOCK
);
1445 err
= WSAEventSelect( socketRef
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
1446 require_errno( err
, errno_compat(), exit
);
1451 TearDownNotifications( inMDNS
);
1456 //===========================================================================================================================
1457 // TearDownNotifications
1458 //===========================================================================================================================
1460 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
1462 SocketRef socketRef
;
1464 socketRef
= inMDNS
->p
->interfaceListChangedSocketRef
;
1465 inMDNS
->p
->interfaceListChangedSocketRef
= kInvalidSocketRef
;
1466 if( IsValidSocket( socketRef
) )
1468 close_compat( socketRef
);
1470 return( mStatus_NoError
);
1477 //===========================================================================================================================
1479 //===========================================================================================================================
1481 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
1484 HANDLE threadHandle
;
1488 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread\n" );
1490 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
1491 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
1493 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1494 require_action( inMDNS
->p
->initEvent
, exit
, err
= mStatus_NoMemoryErr
);
1495 inMDNS
->p
->initStatus
= mStatus_Invalid
;
1497 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1498 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1500 threadHandle
= (HANDLE
) _beginthreadex( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
1501 require_action( threadHandle
, exit
, err
= mStatus_NoMemoryErr
);
1503 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
1504 require_action( result
== WAIT_OBJECT_0
, exit
, err
= mStatus_UnknownErr
);
1505 err
= inMDNS
->p
->initStatus
;
1506 require_noerr( err
, exit
);
1509 if( inMDNS
->p
->initEvent
)
1511 CloseHandle( inMDNS
->p
->initEvent
);
1512 inMDNS
->p
->initEvent
= 0;
1514 dlog( kDebugLevelVerbose
, DEBUG_NAME
"setting up thread done (err=%ld)\n", err
);
1518 //===========================================================================================================================
1520 //===========================================================================================================================
1522 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
1526 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
1527 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
1529 if( inMDNS
->p
->cancelEvent
)
1533 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
1536 if( inMDNS
->p
->quitEvent
)
1538 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
1539 check( result
== WAIT_OBJECT_0
);
1542 return( mStatus_NoError
);
1545 //===========================================================================================================================
1547 //===========================================================================================================================
1549 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
1561 m
= (mDNS
*) inParam
;
1562 err
= ProcessingThreadInitialize( m
);
1563 require_noerr( err
, exit
);
1568 // Set up the list of objects we'll be waiting on.
1572 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
1573 require_noerr( err
, exit
);
1575 // Main processing loop.
1579 // Give the mDNS core a chance to do its work and determine next event time.
1581 mDNSs32 interval
= mDNS_Execute(m
) - mDNSPlatformTimeNow();
1582 if (interval
< 0) interval
= 0;
1583 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
1584 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
1586 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1588 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
1589 if( result
== WAIT_TIMEOUT
)
1591 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1593 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
1596 else if( result
== kWaitListCancelEvent
)
1598 // Cancel event. Set the done flag and break to exit.
1600 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
1604 else if( result
== kWaitListInterfaceListChangedEvent
)
1606 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1608 ProcessingThreadInterfaceListChanged( m
);
1611 else if( result
== kWaitListWakeupEvent
)
1613 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
1615 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup\n" );
1622 // Socket data available event. Determine which socket and process the packet.
1624 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
1625 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
1626 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
1627 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
1629 HANDLE signaledObject
;
1631 mDNSInterfaceData
* ifd
;
1633 signaledObject
= waitList
[ waitItemIndex
];
1636 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1638 if( ifd
->multicastReadPendingEvent
== signaledObject
)
1640 ProcessingThreadProcessPacket( m
, ifd
, ifd
->multicastSocketRef
);
1643 if( ifd
->unicastReadPendingEvent
== signaledObject
)
1645 ProcessingThreadProcessPacket( m
, ifd
, ifd
->unicastSocketRef
);
1653 // Unexpected wait result.
1655 dlog( kDebugLevelAllowedError
, DEBUG_NAME
"unexpected wait result (result=0x%08X)\n", result
);
1660 // Release the wait list.
1670 // Signal the quit event to indicate that the thread is finished.
1673 wasSet
= SetEvent( m
->p
->quitEvent
);
1676 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
1677 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1683 //===========================================================================================================================
1684 // ProcessingThreadInitialize
1685 //===========================================================================================================================
1687 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
1692 inMDNS
->p
->threadID
= GetCurrentThreadId();
1694 err
= SetupInterfaceList( inMDNS
);
1695 require_noerr( err
, exit
);
1700 TearDownInterfaceList( inMDNS
);
1702 inMDNS
->p
->initStatus
= err
;
1703 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
1709 //===========================================================================================================================
1710 // ProcessingThreadSetupWaitList
1711 //===========================================================================================================================
1713 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
1718 HANDLE
* waitItemPtr
;
1719 mDNSInterfaceData
* ifd
;
1721 dlog( kDebugLevelVerbose
, DEBUG_NAME
"thread setting up wait list\n" );
1724 check( outWaitList
);
1725 check( outWaitListCount
);
1727 // Allocate an array to hold all the objects to wait on.
1729 waitListCount
= kWaitListFixedItemCount
+ ( 2 * inMDNS
->p
->interfaceCount
);
1730 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
1731 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
1732 waitItemPtr
= waitList
;
1734 // Add the fixed wait items to the beginning of the list.
1736 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
1737 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
1738 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
1740 // Append all the dynamic wait items to the list.
1742 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1744 *waitItemPtr
++ = ifd
->multicastReadPendingEvent
;
1745 *waitItemPtr
++ = ifd
->unicastReadPendingEvent
;
1748 *outWaitList
= waitList
;
1749 *outWaitListCount
= waitListCount
;
1751 err
= mStatus_NoError
;
1758 dlog( kDebugLevelVerbose
, DEBUG_NAME
"thread setting up wait list done (err=%ld)\n", err
);
1762 //===========================================================================================================================
1763 // ProcessingThreadProcessPacket
1764 //===========================================================================================================================
1766 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSocketRef
)
1769 mDNSBool isMulticast
;
1771 struct sockaddr_in addr
;
1773 mDNSu8
* packetEndPtr
;
1779 isMulticast
= (mDNSBool
)( inSocketRef
== inIFD
->multicastSocketRef
);
1781 // Receive the packet.
1783 addrSize
= sizeof( addr
);
1784 n
= recvfrom( inSocketRef
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
1788 // Set up the src/dst/interface info.
1790 srcAddr
.type
= mDNSAddrType_IPv4
;
1791 srcAddr
.ip
.v4
.NotAnInteger
= addr
.sin_addr
.s_addr
;
1792 srcPort
.NotAnInteger
= addr
.sin_port
;
1793 dstAddr
.type
= mDNSAddrType_IPv4
;
1794 dstAddr
.ip
.v4
= isMulticast
? AllDNSLinkGroup
: inIFD
->hostSet
.ip
.ip
.v4
;
1795 dstPort
= isMulticast
? MulticastDNSPort
: UnicastDNSPort
;
1797 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
1798 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
1799 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %u.%u.%u.%u:%u\n",
1800 srcAddr
.ip
.v4
.b
[ 0 ], srcAddr
.ip
.v4
.b
[ 1 ], srcAddr
.ip
.v4
.b
[ 2 ], srcAddr
.ip
.v4
.b
[ 3 ],
1801 ntohs( srcPort
.NotAnInteger
) );
1802 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %u.%u.%u.%u:%u\n",
1803 dstAddr
.ip
.v4
.b
[ 0 ], dstAddr
.ip
.v4
.b
[ 1 ], dstAddr
.ip
.v4
.b
[ 2 ], dstAddr
.ip
.v4
.b
[ 3 ],
1804 ntohs( dstPort
.NotAnInteger
) );
1805 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %u.%u.%u.%u\n",
1806 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 0 ], inIFD
->hostSet
.ip
.ip
.v4
.b
[ 1 ],
1807 inIFD
->hostSet
.ip
.ip
.v4
.b
[ 2 ], inIFD
->hostSet
.ip
.ip
.v4
.b
[ 3 ] );
1809 dlog( kDebugLevelChatty
, DEBUG_NAME
"--\n" );
1811 // Dispatch the packet to mDNS.
1813 packetEndPtr
= ( (mDNSu8
*) &packet
) + n
;
1814 mDNSCoreReceive( inMDNS
, &packet
, packetEndPtr
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inIFD
->hostSet
.InterfaceID
, 255 );
1819 inIFD
->recvMulticastCounter
+= isMulticast
;
1820 inIFD
->recvUnicastCounter
+= !isMulticast
;
1821 inIFD
->recvErrorCounter
+= ( n
< 0 );
1824 //===========================================================================================================================
1825 // ProcessingThreadInterfaceListChanged
1826 //===========================================================================================================================
1828 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
1832 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed event\n" );
1835 mDNSPlatformLock( inMDNS
);
1837 // Tear down the existing interfaces and set up new ones using the new IP info.
1839 err
= TearDownInterfaceList( inMDNS
);
1842 err
= SetupInterfaceList( inMDNS
);
1845 mDNSPlatformUnlock( inMDNS
);
1847 // Inform clients of the change.
1849 if( inMDNS
->MainCallback
)
1851 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1854 // Force mDNS to update.
1856 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
1861 #pragma mark == Utilities ==
1864 #if( defined( _WIN32_WCE ) )
1865 //===========================================================================================================================
1867 //===========================================================================================================================
1869 int getifaddrs( struct ifaddrs
**outAddrs
)
1875 SOCKET_ADDRESS_LIST
* addressList
;
1876 struct ifaddrs
* head
;
1877 struct ifaddrs
** next
;
1878 struct ifaddrs
* ifa
;
1882 sock
= kInvalidSocketRef
;
1887 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
1889 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1890 require_action( IsValidSocket( sock
), exit
, err
= mStatus_NoMemoryErr
);
1892 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
1893 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
1895 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
1898 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
1899 require_action( size
> 0, exit
, err
= -1 );
1902 buffer
= malloc( size
);
1903 require_action( buffer
, exit
, err
= -1 );
1905 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
1907 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
1908 require_noerr( err
, exit
);
1909 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
1911 // Process the raw interface list and build a linked list of interfaces.
1913 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
1915 n
= addressList
->iAddressCount
;
1920 for( i
= 0; i
< n
; ++i
)
1922 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
1923 require_action( ifa
, exit
, err
= WSAENOBUFS
);
1926 next
= &ifa
->ifa_next
;
1928 // Fetch the name. $$$ TO DO: Get the real name of the interface.
1930 ifa
->ifa_name
= (char *) malloc( 16 );
1931 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
1932 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
1934 // Fetch flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
1936 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
1940 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
1944 struct sockaddr_in
* sinptr4
;
1946 sinptr4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
1947 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
1948 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
1949 memcpy( ifa
->ifa_addr
, sinptr4
, sizeof( *sinptr4
) );
1970 freeifaddrs( head
);
1976 if( sock
!= INVALID_SOCKET
)
1978 closesocket( sock
);
1982 #endif // defined( _WIN32_WCE ) )
1984 #if( !defined( _WIN32_WCE ) )
1985 //===========================================================================================================================
1987 //===========================================================================================================================
1989 int getifaddrs( struct ifaddrs
**outAddrs
)
1995 INTERFACE_INFO
* buffer
;
1996 INTERFACE_INFO
* tempBuffer
;
1997 INTERFACE_INFO
* ifInfo
;
2000 struct ifaddrs
* head
;
2001 struct ifaddrs
** next
;
2002 struct ifaddrs
* ifa
;
2003 struct sockaddr_in
* sinptr4
;
2004 struct sockaddr_in6_old
* sinptr6
;
2005 struct sockaddr
* sa
;
2007 sock
= INVALID_SOCKET
;
2012 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
2013 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
2014 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
2016 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2017 require_action( sock
!= INVALID_SOCKET
, exit
, err
= WSAEMFILE
);
2020 size
= 16 * sizeof( INTERFACE_INFO
);
2023 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
2024 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
2025 buffer
= tempBuffer
;
2027 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
2034 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
2036 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
2038 check( actualSize
<= size
);
2039 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
2040 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
2042 // Process the raw interface list and build a linked list of interfaces.
2044 for( i
= 0; i
< n
; ++i
)
2046 ifInfo
= &buffer
[ i
];
2048 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
2049 require_action( ifa
, exit
, err
= WSAENOBUFS
);
2052 next
= &ifa
->ifa_next
;
2054 // Fetch the name. $$$ TO DO: Get the real name of the interface.
2056 ifa
->ifa_name
= (char *) malloc( 16 );
2057 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
2058 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
2060 // Fetch interface flags.
2062 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
2066 switch( ifInfo
->iiAddress
.Address
.sa_family
)
2069 sinptr4
= &ifInfo
->iiAddress
.AddressIn
;
2070 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
2071 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
2072 memcpy( ifa
->ifa_addr
, sinptr4
, sizeof( *sinptr4
) );
2074 if( ifInfo
->iiNetmask
.Address
.sa_family
== AF_INET
)
2076 sinptr4
= &ifInfo
->iiNetmask
.AddressIn
;
2077 ifa
->ifa_netmask
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
2078 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
2079 memcpy( ifa
->ifa_netmask
, sinptr4
, sizeof( *sinptr4
) );
2082 if( ifInfo
->iiBroadcastAddress
.Address
.sa_family
== AF_INET
)
2084 sinptr4
= &ifInfo
->iiBroadcastAddress
.AddressIn
;
2085 ifa
->ifa_broadaddr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr4
) );
2086 require_action( ifa
->ifa_broadaddr
, exit
, err
= WSAENOBUFS
);
2087 memcpy( ifa
->ifa_broadaddr
, sinptr4
, sizeof( *sinptr4
) );
2092 sinptr6
= &ifInfo
->iiAddress
.AddressIn6
;
2093 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sinptr6
) );
2094 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
2095 memcpy( ifa
->ifa_addr
, sinptr6
, sizeof( *sinptr6
) );
2099 sa
= &ifInfo
->iiAddress
.Address
;
2100 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa
) );
2101 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
2102 memcpy( ifa
->ifa_addr
, sa
, sizeof( *sa
) );
2119 freeifaddrs( head
);
2125 if( sock
!= INVALID_SOCKET
)
2127 closesocket( sock
);
2131 #endif // !defined( _WIN32_WCE ) )
2133 //===========================================================================================================================
2135 //===========================================================================================================================
2137 void freeifaddrs( struct ifaddrs
*inAddrs
)
2142 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
2144 for( p
= inAddrs
; p
; p
= q
)
2150 free( p
->ifa_name
);
2155 free( p
->ifa_addr
);
2158 if( p
->ifa_netmask
)
2160 free( p
->ifa_netmask
);
2161 p
->ifa_netmask
= NULL
;
2163 if( p
->ifa_broadaddr
)
2165 free( p
->ifa_broadaddr
);
2166 p
->ifa_broadaddr
= NULL
;
2168 if( p
->ifa_dstaddr
)
2170 free( p
->ifa_dstaddr
);
2171 p
->ifa_dstaddr
= NULL
;
2175 free( p
->ifa_data
);
2182 #if( !defined( _WIN32_WCE ) )
2183 //===========================================================================================================================
2185 //===========================================================================================================================
2187 int sock_pton( const char *inString
, int inFamily
, void *outAddr
, size_t inAddrSize
, size_t *outAddrSize
)
2192 if( inAddrSize
== 0 )
2194 if( inFamily
== AF_INET
)
2196 inAddrSize
= sizeof( struct sockaddr_in
);
2198 else if( inFamily
== AF_INET6
)
2200 inAddrSize
= sizeof( struct sockaddr_in6
);
2204 err
= WSAEAFNOSUPPORT
;
2208 size
= (int) inAddrSize
;
2210 err
= WSAStringToAddressA( (char *) inString
, inFamily
, NULL
, (LPSOCKADDR
) outAddr
, &size
);
2211 if( err
!= 0 ) goto exit
;
2215 *outAddrSize
= (size_t) size
;
2222 //===========================================================================================================================
2224 //===========================================================================================================================
2226 char * sock_ntop( const void *inAddr
, size_t inAddrSize
, char *inBuffer
, size_t inBufferSize
)
2232 if( inAddrSize
== 0 )
2234 const struct sockaddr
* addr
;
2236 addr
= (const struct sockaddr
*) inAddr
;
2237 if( addr
->sa_family
== AF_INET
)
2239 size
= sizeof( struct sockaddr_in
);
2241 else if( addr
->sa_family
== AF_INET6
)
2243 size
= sizeof( struct sockaddr_in6
);
2247 WSASetLastError( WSAEAFNOSUPPORT
);
2254 size
= (DWORD
) inAddrSize
;
2257 stringSize
= (DWORD
) inBufferSize
;
2258 err
= WSAAddressToStringA( (LPSOCKADDR
) inAddr
, size
, NULL
, inBuffer
, &stringSize
);
2267 #endif // !defined( _WIN32_WCE )