Home | History | Annotate | Download | only in mDNSWindows
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16 
     17 	To Do:
     18 
     19 	- Get unicode name of machine for nice name instead of just the host name.
     20 	- Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
     21 	- Get DNS server address(es) from Windows and provide them to the uDNS layer.
     22 	- Implement TCP support for truncated packets (only stubs now).
     23 
     24 */
     25 
     26 #include	<stdarg.h>
     27 #include	<stddef.h>
     28 #include	<stdio.h>
     29 #include	<stdlib.h>
     30 #include	<crtdbg.h>
     31 #include	<string.h>
     32 
     33 #include	"CommonServices.h"
     34 #include	"DebugServices.h"
     35 #include	"Firewall.h"
     36 #include	"RegNames.h"
     37 #include	"Secret.h"
     38 #include	<dns_sd.h>
     39 
     40 #include	<Iphlpapi.h>
     41 #include	<mswsock.h>
     42 #include	<process.h>
     43 #include	<ntsecapi.h>
     44 #include	<lm.h>
     45 #include	<winioctl.h>
     46 #include	<ntddndis.h>        // This defines the IOCTL constants.
     47 
     48 #include	"mDNSEmbeddedAPI.h"
     49 #include	"GenLinkedList.h"
     50 #include	"DNSCommon.h"
     51 #include	"mDNSWin32.h"
     52 
     53 #if 0
     54 #pragma mark == Constants ==
     55 #endif
     56 
     57 //===========================================================================================================================
     58 //	Constants
     59 //===========================================================================================================================
     60 
     61 #define	DEBUG_NAME									"[mDNSWin32] "
     62 
     63 #define	MDNS_WINDOWS_USE_IPV6_IF_ADDRS				1
     64 #define	MDNS_WINDOWS_ENABLE_IPV4					1
     65 #define	MDNS_WINDOWS_ENABLE_IPV6					1
     66 #define	MDNS_FIX_IPHLPAPI_PREFIX_BUG				1
     67 #define MDNS_SET_HINFO_STRINGS						0
     68 
     69 #define	kMDNSDefaultName							"My Computer"
     70 
     71 #define	kWinSockMajorMin							2
     72 #define	kWinSockMinorMin							2
     73 
     74 #define kRegistryMaxKeyLength						255
     75 #define kRegistryMaxValueName						16383
     76 
     77 static GUID											kWSARecvMsgGUID = WSAID_WSARECVMSG;
     78 
     79 #define kIPv6IfIndexBase							(10000000L)
     80 #define SMBPortAsNumber								445
     81 #define DEVICE_PREFIX								"\\\\.\\"
     82 
     83 #if 0
     84 #pragma mark == Prototypes ==
     85 #endif
     86 
     87 //===========================================================================================================================
     88 //	Prototypes
     89 //===========================================================================================================================
     90 
     91 mDNSlocal mStatus			SetupNiceName( mDNS * const inMDNS );
     92 mDNSlocal mStatus			SetupHostName( mDNS * const inMDNS );
     93 mDNSlocal mStatus			SetupName( mDNS * const inMDNS );
     94 mDNSlocal mStatus			SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
     95 mDNSlocal mStatus			TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
     96 mDNSlocal void CALLBACK		FreeInterface( mDNSInterfaceData *inIFD );
     97 mDNSlocal mStatus			SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  );
     98 mDNSlocal mStatus			SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
     99 mDNSlocal OSStatus			GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
    100 mDNSlocal int				getifaddrs( struct ifaddrs **outAddrs );
    101 mDNSlocal void				freeifaddrs( struct ifaddrs *inAddrs );
    102 
    103 
    104 
    105 // Platform Accessors
    106 
    107 #ifdef	__cplusplus
    108 	extern "C" {
    109 #endif
    110 
    111 typedef struct mDNSPlatformInterfaceInfo	mDNSPlatformInterfaceInfo;
    112 struct	mDNSPlatformInterfaceInfo
    113 {
    114 	const char *		name;
    115 	mDNSAddr			ip;
    116 };
    117 
    118 
    119 mDNSexport mStatus	mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
    120 mDNSexport mStatus	mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
    121 
    122 // Utilities
    123 
    124 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
    125 	mDNSlocal int	getifaddrs_ipv6( struct ifaddrs **outAddrs );
    126 #endif
    127 
    128 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
    129 
    130 
    131 mDNSlocal DWORD				GetPrimaryInterface();
    132 mDNSlocal mStatus			AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
    133 mDNSlocal mDNSBool			CanReceiveUnicast( void );
    134 mDNSlocal mDNSBool			IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
    135 
    136 mDNSlocal mStatus			StringToAddress( mDNSAddr * ip, LPSTR string );
    137 mDNSlocal mStatus			RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
    138 mDNSlocal struct ifaddrs*	myGetIfAddrs(int refresh);
    139 mDNSlocal OSStatus			TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
    140 mDNSlocal OSStatus			WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
    141 mDNSlocal void				TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context );
    142 mDNSlocal void				TCPCanRead( TCPSocket * sock );
    143 mDNSlocal mStatus			TCPBeginRecv( TCPSocket * sock );
    144 mDNSlocal void CALLBACK		TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
    145 mDNSlocal void				TCPCloseSocket( TCPSocket * socket );
    146 mDNSlocal void CALLBACK		TCPFreeSocket( TCPSocket *sock );
    147 mDNSlocal OSStatus			UDPBeginRecv( UDPSocket * socket );
    148 mDNSlocal void CALLBACK		UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
    149 mDNSlocal void				UDPCloseSocket( UDPSocket * sock );
    150 mDNSlocal void CALLBACK		UDPFreeSocket( UDPSocket * sock );
    151 mDNSlocal mStatus           SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
    152 mDNSlocal void				GetDDNSFQDN( domainname *const fqdn );
    153 #ifdef UNICODE
    154 mDNSlocal void				GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
    155 #else
    156 mDNSlocal void				GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
    157 #endif
    158 mDNSlocal void				SetDomainSecrets( mDNS * const inMDNS );
    159 mDNSlocal void				SetDomainSecret( mDNS * const m, const domainname * inDomain );
    160 mDNSlocal VOID CALLBACK		CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
    161 mDNSlocal void				CheckFileShares( mDNS * const inMDNS );
    162 mDNSlocal void				SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
    163 mDNSlocal mDNSu8			IsWOMPEnabledForAdapter( const char * adapterName );
    164 mDNSlocal void				DispatchUDPEvent( mDNS * const m, UDPSocket * sock );
    165 mDNSlocal void				DispatchTCPEvent( mDNS * const m, TCPSocket * sock );
    166 
    167 #ifdef	__cplusplus
    168 	}
    169 #endif
    170 
    171 #if 0
    172 #pragma mark == Globals ==
    173 #endif
    174 
    175 //===========================================================================================================================
    176 //	Globals
    177 //===========================================================================================================================
    178 
    179 mDNSlocal mDNS_PlatformSupport	gMDNSPlatformSupport;
    180 mDNSs32							mDNSPlatformOneSecond	= 0;
    181 mDNSlocal UDPSocket		*		gUDPSockets				= NULL;
    182 mDNSlocal int					gUDPNumSockets			= 0;
    183 mDNSlocal GenLinkedList			gUDPDispatchableSockets;
    184 mDNSlocal GenLinkedList			gTCPDispatchableSockets;
    185 
    186 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
    187 
    188 	typedef DWORD
    189 		( WINAPI * GetAdaptersAddressesFunctionPtr )(
    190 			ULONG 					inFamily,
    191 			DWORD 					inFlags,
    192 			PVOID 					inReserved,
    193 			PIP_ADAPTER_ADDRESSES 	inAdapter,
    194 			PULONG					outBufferSize );
    195 
    196 	mDNSlocal HMODULE								gIPHelperLibraryInstance			= NULL;
    197 	mDNSlocal GetAdaptersAddressesFunctionPtr		gGetAdaptersAddressesFunctionPtr	= NULL;
    198 
    199 #endif
    200 
    201 
    202 #ifndef HCRYPTPROV
    203    typedef ULONG_PTR HCRYPTPROV;    // WinCrypt.h, line 249
    204 #endif
    205 
    206 
    207 #ifndef CRYPT_MACHINE_KEYSET
    208 #	define CRYPT_MACHINE_KEYSET    0x00000020
    209 #endif
    210 
    211 #ifndef CRYPT_NEWKEYSET
    212 #	define CRYPT_NEWKEYSET         0x00000008
    213 #endif
    214 
    215 #ifndef PROV_RSA_FULL
    216 #  define PROV_RSA_FULL 1
    217 #endif
    218 
    219 typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
    220 typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
    221 typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
    222 
    223 static fnCryptAcquireContext g_lpCryptAcquireContext 	= NULL;
    224 static fnCryptReleaseContext g_lpCryptReleaseContext 	= NULL;
    225 static fnCryptGenRandom		 g_lpCryptGenRandom 		= NULL;
    226 static HINSTANCE			 g_hAAPI32 					= NULL;
    227 static HCRYPTPROV			 g_hProvider 				= ( ULONG_PTR ) NULL;
    228 
    229 
    230 typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
    231     (
    232     DNSServiceRef                       *sdRef,
    233     DNSServiceFlags                     flags,
    234     uint32_t                            interfaceIndex,
    235     const char                          *name,         /* may be NULL */
    236     const char                          *regtype,
    237     const char                          *domain,       /* may be NULL */
    238     const char                          *host,         /* may be NULL */
    239     uint16_t                            port,
    240     uint16_t                            txtLen,
    241     const void                          *txtRecord,    /* may be NULL */
    242     DNSServiceRegisterReply             callBack,      /* may be NULL */
    243     void                                *context       /* may be NULL */
    244     );
    245 
    246 
    247 typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
    248 
    249 mDNSlocal HMODULE					gDNSSDLibrary				= NULL;
    250 mDNSlocal DNSServiceRegisterFunc	gDNSServiceRegister			= NULL;
    251 mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate	= NULL;
    252 mDNSlocal HANDLE					gSMBThread					= NULL;
    253 mDNSlocal HANDLE					gSMBThreadRegisterEvent		= NULL;
    254 mDNSlocal HANDLE					gSMBThreadDeregisterEvent	= NULL;
    255 mDNSlocal HANDLE					gSMBThreadStopEvent			= NULL;
    256 mDNSlocal HANDLE					gSMBThreadQuitEvent			= NULL;
    257 
    258 #define	kSMBStopEvent				( WAIT_OBJECT_0 + 0 )
    259 #define	kSMBRegisterEvent			( WAIT_OBJECT_0 + 1 )
    260 #define kSMBDeregisterEvent			( WAIT_OBJECT_0 + 2 )
    261 
    262 
    263 #if 0
    264 #pragma mark -
    265 #pragma mark == Platform Support ==
    266 #endif
    267 
    268 //===========================================================================================================================
    269 //	mDNSPlatformInit
    270 //===========================================================================================================================
    271 
    272 mDNSexport mStatus	mDNSPlatformInit( mDNS * const inMDNS )
    273 {
    274 	mStatus		err;
    275 	WSADATA		wsaData;
    276 	int			supported;
    277 	struct sockaddr_in	sa4;
    278 	struct sockaddr_in6 sa6;
    279 	int					sa4len;
    280 	int					sa6len;
    281 	DWORD				size;
    282 	DWORD				val;
    283 
    284 	dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
    285 
    286 	// Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
    287 	// calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
    288 
    289 	mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
    290 	if( !inMDNS->p ) inMDNS->p				= &gMDNSPlatformSupport;
    291 	inMDNS->p->mainThread					= OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
    292 	require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
    293 	inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
    294 	require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
    295 	inMDNS->p->checkFileSharesTimeout		= 10;		// Retry time for CheckFileShares() in seconds
    296 	mDNSPlatformOneSecond 					= 1000;		// Use milliseconds as the quantum of time
    297 	InitLinkedList( &gTCPDispatchableSockets, offsetof( TCPSocket, nextDispatchable ) );
    298 	InitLinkedList( &gUDPDispatchableSockets, offsetof( UDPSocket, nextDispatchable ) );
    299 
    300 	// Startup WinSock 2.2 or later.
    301 
    302 	err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
    303 	require_noerr( err, exit );
    304 
    305 	supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
    306 	require_action( supported, exit, err = mStatus_UnsupportedErr );
    307 
    308 	inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
    309 
    310 	// Setup the HINFO HW strings.
    311 	//<rdar://problem/7245119> device-info should have model=Windows
    312 
    313 	strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
    314 	inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
    315 	dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
    316 
    317 	// Setup the HINFO SW strings.
    318 #if ( MDNS_SET_HINFO_STRINGS )
    319 	mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
    320 		"mDNSResponder (%s %s)", __DATE__, __TIME__ );
    321 	inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
    322 	dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
    323 #endif
    324 
    325 	// Set the thread global overlapped flag
    326 
    327 	val = 0;
    328 	err = setsockopt( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, ( char* ) &val, sizeof( val ) );
    329 	err = translate_errno( err != SOCKET_ERROR, WSAGetLastError(), kUnknownErr );
    330 	require_noerr( err, exit );
    331 
    332 	// Set up the IPv4 unicast socket
    333 
    334 	inMDNS->p->unicastSock4.fd			= INVALID_SOCKET;
    335 	inMDNS->p->unicastSock4.recvMsgPtr	= NULL;
    336 	inMDNS->p->unicastSock4.ifd			= NULL;
    337 	inMDNS->p->unicastSock4.overlapped.pending = FALSE;
    338 	inMDNS->p->unicastSock4.next		= NULL;
    339 	inMDNS->p->unicastSock4.m			= inMDNS;
    340 
    341 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
    342 
    343 	sa4.sin_family		= AF_INET;
    344 	sa4.sin_addr.s_addr = INADDR_ANY;
    345 	err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
    346 	check_noerr( err );
    347 	sa4len = sizeof( sa4 );
    348 	err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
    349 	require_noerr( err, exit );
    350 	inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
    351 	inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
    352 	err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
    353 
    354 	if ( err )
    355 	{
    356 		inMDNS->p->unicastSock4.recvMsgPtr = NULL;
    357 	}
    358 
    359 	err = UDPBeginRecv( &inMDNS->p->unicastSock4 );
    360 	require_noerr( err, exit );
    361 
    362 #endif
    363 
    364 	// Set up the IPv6 unicast socket
    365 
    366 	inMDNS->p->unicastSock6.fd			= INVALID_SOCKET;
    367 	inMDNS->p->unicastSock6.recvMsgPtr	= NULL;
    368 	inMDNS->p->unicastSock6.ifd			= NULL;
    369 	inMDNS->p->unicastSock6.overlapped.pending = FALSE;
    370 	inMDNS->p->unicastSock6.next		= NULL;
    371 	inMDNS->p->unicastSock6.m			= inMDNS;
    372 
    373 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
    374 
    375 	sa6.sin6_family		= AF_INET6;
    376 	sa6.sin6_addr		= in6addr_any;
    377 	sa6.sin6_scope_id	= 0;
    378 
    379 	// This call will fail if the machine hasn't installed IPv6.  In that case,
    380 	// the error will be WSAEAFNOSUPPORT.
    381 
    382 	err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
    383 	require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
    384 	err = kNoErr;
    385 
    386 	// If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
    387 
    388 	if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
    389 	{
    390 		sa6len = sizeof( sa6 );
    391 		err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
    392 		require_noerr( err, exit );
    393 		inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
    394 		inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
    395 
    396 		err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
    397 
    398 		if ( err != 0 )
    399 		{
    400 			inMDNS->p->unicastSock6.recvMsgPtr = NULL;
    401 		}
    402 
    403 		err = UDPBeginRecv( &inMDNS->p->unicastSock6 );
    404 		require_noerr( err, exit );
    405 	}
    406 
    407 #endif
    408 
    409 	// Notify core of domain secret keys
    410 
    411 	SetDomainSecrets( inMDNS );
    412 
    413 	// Success!
    414 
    415 	mDNSCoreInitComplete( inMDNS, err );
    416 
    417 
    418 exit:
    419 
    420 	if ( err )
    421 	{
    422 		mDNSPlatformClose( inMDNS );
    423 	}
    424 
    425 	dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
    426 	return( err );
    427 }
    428 
    429 //===========================================================================================================================
    430 //	mDNSPlatformClose
    431 //===========================================================================================================================
    432 
    433 mDNSexport void	mDNSPlatformClose( mDNS * const inMDNS )
    434 {
    435 	mStatus		err;
    436 
    437 	dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
    438 	check( inMDNS );
    439 
    440 	if ( gSMBThread != NULL )
    441 	{
    442 		dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
    443 		SetEvent( gSMBThreadStopEvent );
    444 
    445 		if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
    446 		{
    447 			if ( gSMBThreadQuitEvent )
    448 			{
    449 				CloseHandle( gSMBThreadQuitEvent );
    450 				gSMBThreadQuitEvent = NULL;
    451 			}
    452 
    453 			if ( gSMBThreadStopEvent )
    454 			{
    455 				CloseHandle( gSMBThreadStopEvent );
    456 				gSMBThreadStopEvent = NULL;
    457 			}
    458 
    459 			if ( gSMBThreadDeregisterEvent )
    460 			{
    461 				CloseHandle( gSMBThreadDeregisterEvent );
    462 				gSMBThreadDeregisterEvent = NULL;
    463 			}
    464 
    465 			if ( gSMBThreadRegisterEvent )
    466 			{
    467 				CloseHandle( gSMBThreadRegisterEvent );
    468 				gSMBThreadRegisterEvent = NULL;
    469 			}
    470 
    471 			if ( gDNSSDLibrary )
    472 			{
    473 				FreeLibrary( gDNSSDLibrary );
    474 				gDNSSDLibrary = NULL;
    475 			}
    476 		}
    477 		else
    478 		{
    479 			LogMsg( "Unable to stop SMBThread" );
    480 		}
    481 
    482 		inMDNS->p->smbFileSharing = mDNSfalse;
    483 		inMDNS->p->smbPrintSharing = mDNSfalse;
    484 	}
    485 
    486 	// Tear everything down in reverse order to how it was set up.
    487 
    488 	err = TearDownInterfaceList( inMDNS );
    489 	check_noerr( err );
    490 	check( !inMDNS->p->inactiveInterfaceList );
    491 
    492 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
    493 
    494 	UDPCloseSocket( &inMDNS->p->unicastSock4 );
    495 
    496 #endif
    497 
    498 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
    499 
    500 	UDPCloseSocket( &inMDNS->p->unicastSock6 );
    501 
    502 #endif
    503 
    504 	// Free the DLL needed for IPv6 support.
    505 
    506 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
    507 	if( gIPHelperLibraryInstance )
    508 	{
    509 		gGetAdaptersAddressesFunctionPtr = NULL;
    510 
    511 		FreeLibrary( gIPHelperLibraryInstance );
    512 		gIPHelperLibraryInstance = NULL;
    513 	}
    514 #endif
    515 
    516 	if ( g_hAAPI32 )
    517 	{
    518 		// Release any resources
    519 
    520 		if ( g_hProvider && g_lpCryptReleaseContext )
    521 		{
    522 			( g_lpCryptReleaseContext )( g_hProvider, 0 );
    523 		}
    524 
    525 		// Free the AdvApi32.dll
    526 
    527 		FreeLibrary( g_hAAPI32 );
    528 
    529 		// And reset all the data
    530 
    531 		g_lpCryptAcquireContext = NULL;
    532 		g_lpCryptReleaseContext = NULL;
    533 		g_lpCryptGenRandom 		= NULL;
    534 		g_hProvider 			= ( ULONG_PTR ) NULL;
    535 		g_hAAPI32				= NULL;
    536 	}
    537 
    538 	// Clear out the APC queue
    539 
    540 	while ( SleepEx( 0, TRUE ) == WAIT_IO_COMPLETION )
    541 	{
    542 		DispatchSocketEvents( inMDNS );
    543 	}
    544 
    545 	WSACleanup();
    546 
    547 	dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
    548 }
    549 
    550 
    551 //===========================================================================================================================
    552 //	mDNSPlatformLock
    553 //===========================================================================================================================
    554 
    555 mDNSexport void	mDNSPlatformLock( const mDNS * const inMDNS )
    556 {
    557 	( void ) inMDNS;
    558 }
    559 
    560 //===========================================================================================================================
    561 //	mDNSPlatformUnlock
    562 //===========================================================================================================================
    563 
    564 mDNSexport void	mDNSPlatformUnlock( const mDNS * const inMDNS )
    565 {
    566 	( void ) inMDNS;
    567 }
    568 
    569 //===========================================================================================================================
    570 //	mDNSPlatformStrCopy
    571 //===========================================================================================================================
    572 
    573 mDNSexport void	mDNSPlatformStrCopy( void *inDst, const void *inSrc )
    574 {
    575 	check( inSrc );
    576 	check( inDst );
    577 
    578 	strcpy( (char *) inDst, (const char*) inSrc );
    579 }
    580 
    581 //===========================================================================================================================
    582 //	mDNSPlatformStrLCopy
    583 //===========================================================================================================================
    584 
    585 mDNSexport mDNSu32 mDNSPlatformStrLCopy(void *inDst, const void *inSrc, mDNSu32 inSize)
    586 {
    587 	const char *		src = (const char *) inSrc;
    588 
    589 	if( inSize > 0 )
    590 	{
    591 		size_t		n;
    592 		char *		dst = (char *) inDst;
    593 
    594 		for( n = inSize - 1; n > 0; --n )
    595 		{
    596 			if( ( *dst++ = *src++ ) == '\0' )
    597 			{
    598 				// Null terminator encountered, so exit.
    599 				goto exit;
    600 			}
    601 		}
    602 		*dst = '\0';
    603 	}
    604 
    605 	while( *src++ != '\0' )
    606 	{
    607 		// Stop at null terminator.
    608 	}
    609 
    610 exit:
    611 	return( (mDNSu32)( src - (const char *) inSrc ) - 1 );
    612 }
    613 
    614 //===========================================================================================================================
    615 //	mDNSPlatformStrLen
    616 //===========================================================================================================================
    617 
    618 mDNSexport mDNSu32	mDNSPlatformStrLen( const void *inSrc )
    619 {
    620 	check( inSrc );
    621 
    622 	return( (mDNSu32) strlen( (const char *) inSrc ) );
    623 }
    624 
    625 //===========================================================================================================================
    626 //	mDNSPlatformMemCopy
    627 //===========================================================================================================================
    628 
    629 mDNSexport void	mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
    630 {
    631 	check( inSrc );
    632 	check( inDst );
    633 
    634 	memcpy( inDst, inSrc, inSize );
    635 }
    636 
    637 //===========================================================================================================================
    638 //	mDNSPlatformMemSame
    639 //===========================================================================================================================
    640 
    641 mDNSexport mDNSBool	mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
    642 {
    643 	check( inSrc );
    644 	check( inDst );
    645 
    646 	return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
    647 }
    648 
    649 //===========================================================================================================================
    650 //	mDNSPlatformMemZero
    651 //===========================================================================================================================
    652 
    653 mDNSexport void	mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
    654 {
    655 	check( inDst );
    656 
    657 	memset( inDst, 0, inSize );
    658 }
    659 
    660 //===========================================================================================================================
    661 //	mDNSPlatformMemAllocate
    662 //===========================================================================================================================
    663 
    664 mDNSexport void *	mDNSPlatformMemAllocate( mDNSu32 inSize )
    665 {
    666 	void *		mem;
    667 
    668 	check( inSize > 0 );
    669 
    670 	mem = malloc( inSize );
    671 	check( mem );
    672 
    673 	return( mem );
    674 }
    675 
    676 //===========================================================================================================================
    677 //	mDNSPlatformMemFree
    678 //===========================================================================================================================
    679 
    680 mDNSexport void	mDNSPlatformMemFree( void *inMem )
    681 {
    682 	check( inMem );
    683 
    684 	free( inMem );
    685 }
    686 
    687 //===========================================================================================================================
    688 //	mDNSPlatformRandomNumber
    689 //===========================================================================================================================
    690 
    691 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
    692 {
    693 	mDNSu32		randomNumber = 0;
    694 	BOOL		bResult;
    695 	OSStatus	err = 0;
    696 
    697 	if ( !g_hAAPI32 )
    698 	{
    699 		g_hAAPI32 = LoadLibrary( TEXT("AdvAPI32.dll") );
    700 		err = translate_errno( g_hAAPI32 != NULL, GetLastError(), mStatus_UnknownErr );
    701 		require_noerr( err, exit );
    702 	}
    703 
    704 	// Function Pointer: CryptAcquireContext
    705 
    706 	if ( !g_lpCryptAcquireContext )
    707 	{
    708 		g_lpCryptAcquireContext = ( fnCryptAcquireContext )
    709 #ifdef UNICODE
    710 			( GetProcAddress( g_hAAPI32, "CryptAcquireContextW" ) );
    711 #else
    712 			( GetProcAddress( g_hAAPI32, "CryptAcquireContextA" ) );
    713 #endif
    714 		err = translate_errno( g_lpCryptAcquireContext != NULL, GetLastError(), mStatus_UnknownErr );
    715 		require_noerr( err, exit );
    716 	}
    717 
    718 	// Function Pointer: CryptReleaseContext
    719 
    720 	if ( !g_lpCryptReleaseContext )
    721 	{
    722 		g_lpCryptReleaseContext = ( fnCryptReleaseContext )
    723          ( GetProcAddress( g_hAAPI32, "CryptReleaseContext" ) );
    724 		err = translate_errno( g_lpCryptReleaseContext != NULL, GetLastError(), mStatus_UnknownErr );
    725 		require_noerr( err, exit );
    726 	}
    727 
    728 	// Function Pointer: CryptGenRandom
    729 
    730 	if ( !g_lpCryptGenRandom )
    731 	{
    732 		g_lpCryptGenRandom = ( fnCryptGenRandom )
    733           ( GetProcAddress( g_hAAPI32, "CryptGenRandom" ) );
    734 		err = translate_errno( g_lpCryptGenRandom != NULL, GetLastError(), mStatus_UnknownErr );
    735 		require_noerr( err, exit );
    736 	}
    737 
    738 	// Setup
    739 
    740 	if ( !g_hProvider )
    741 	{
    742 		bResult = (*g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET );
    743 
    744 		if ( !bResult )
    745 		{
    746 			bResult =  ( *g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET );
    747 			err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
    748 			require_noerr( err, exit );
    749 		}
    750 	}
    751 
    752 	bResult = (*g_lpCryptGenRandom)( g_hProvider, sizeof( randomNumber ), ( BYTE* ) &randomNumber );
    753 	err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
    754 	require_noerr( err, exit );
    755 
    756 exit:
    757 
    758 	if ( err )
    759 	{
    760 		randomNumber = rand();
    761 	}
    762 
    763 	return randomNumber;
    764 }
    765 
    766 //===========================================================================================================================
    767 //	mDNSPlatformTimeInit
    768 //===========================================================================================================================
    769 
    770 mDNSexport mStatus	mDNSPlatformTimeInit( void )
    771 {
    772 	// No special setup is required on Windows -- we just use GetTickCount().
    773 	return( mStatus_NoError );
    774 }
    775 
    776 //===========================================================================================================================
    777 //	mDNSPlatformRawTime
    778 //===========================================================================================================================
    779 
    780 mDNSexport mDNSs32	mDNSPlatformRawTime( void )
    781 {
    782 	return( (mDNSs32) GetTickCount() );
    783 }
    784 
    785 //===========================================================================================================================
    786 //	mDNSPlatformUTC
    787 //===========================================================================================================================
    788 
    789 mDNSexport mDNSs32	mDNSPlatformUTC( void )
    790 {
    791 	return ( mDNSs32 ) time( NULL );
    792 }
    793 
    794 //===========================================================================================================================
    795 //	mDNSPlatformInterfaceNameToID
    796 //===========================================================================================================================
    797 
    798 mDNSexport mStatus	mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
    799 {
    800 	mStatus					err;
    801 	mDNSInterfaceData *		ifd;
    802 
    803 	check( inMDNS );
    804 	check( inMDNS->p );
    805 	check( inName );
    806 
    807 	// Search for an interface with the specified name,
    808 
    809 	for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
    810 	{
    811 		if( strcmp( ifd->name, inName ) == 0 )
    812 		{
    813 			break;
    814 		}
    815 	}
    816 	require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
    817 
    818 	// Success!
    819 
    820 	if( outID )
    821 	{
    822 		*outID = (mDNSInterfaceID) ifd;
    823 	}
    824 	err = mStatus_NoError;
    825 
    826 exit:
    827 	return( err );
    828 }
    829 
    830 //===========================================================================================================================
    831 //	mDNSPlatformInterfaceIDToInfo
    832 //===========================================================================================================================
    833 
    834 mDNSexport mStatus	mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
    835 {
    836 	mStatus					err;
    837 	mDNSInterfaceData *		ifd;
    838 
    839 	check( inMDNS );
    840 	check( inID );
    841 	check( outInfo );
    842 
    843 	// Search for an interface with the specified ID,
    844 
    845 	for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
    846 	{
    847 		if( ifd == (mDNSInterfaceData *) inID )
    848 		{
    849 			break;
    850 		}
    851 	}
    852 	require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
    853 
    854 	// Success!
    855 
    856 	outInfo->name 	= ifd->name;
    857 	outInfo->ip 	= ifd->interfaceInfo.ip;
    858 	err 			= mStatus_NoError;
    859 
    860 exit:
    861 	return( err );
    862 }
    863 
    864 //===========================================================================================================================
    865 //	mDNSPlatformInterfaceIDfromInterfaceIndex
    866 //===========================================================================================================================
    867 
    868 mDNSexport mDNSInterfaceID	mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
    869 {
    870 	mDNSInterfaceID		id;
    871 
    872 	id = mDNSNULL;
    873 	if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
    874 	{
    875 		id = mDNSInterface_LocalOnly;
    876 	}
    877 	/* uncomment if Windows ever supports P2P
    878 	else if( inIndex == kDNSServiceInterfaceIndexP2P )
    879 	{
    880 		id = mDNSInterface_P2P;
    881 	}
    882 	*/
    883 	else if( inIndex != 0 )
    884 	{
    885 		mDNSInterfaceData *		ifd;
    886 
    887 		for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
    888 		{
    889 			if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
    890 			{
    891 				id = ifd->interfaceInfo.InterfaceID;
    892 				break;
    893 			}
    894 		}
    895 		check( ifd );
    896 	}
    897 	return( id );
    898 }
    899 
    900 //===========================================================================================================================
    901 //	mDNSPlatformInterfaceIndexfromInterfaceID
    902 //===========================================================================================================================
    903 
    904 mDNSexport mDNSu32	mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSBool suppressNetworkChange )
    905 {
    906 	mDNSu32		index;
    907 	(void) suppressNetworkChange; // Unused
    908 
    909 	index = 0;
    910 	if( inID == mDNSInterface_LocalOnly )
    911 	{
    912 		index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
    913 	}
    914 	/* uncomment if Windows ever supports P2P
    915 	else if( inID == mDNSInterface_P2P )
    916 	{
    917 		index = (mDNSu32) kDNSServiceInterfaceIndexP2P;
    918 	}
    919 	*/
    920 	else if( inID )
    921 	{
    922 		mDNSInterfaceData *		ifd;
    923 
    924 		// Search active interfaces.
    925 		for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
    926 		{
    927 			if( (mDNSInterfaceID) ifd == inID )
    928 			{
    929 				index = ifd->scopeID;
    930 				break;
    931 			}
    932 		}
    933 
    934 		// Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
    935 
    936 		if( !ifd )
    937 		{
    938 			for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
    939 			{
    940 				if( (mDNSInterfaceID) ifd == inID )
    941 				{
    942 					index = ifd->scopeID;
    943 					break;
    944 				}
    945 			}
    946 		}
    947 		check( ifd );
    948 	}
    949 	return( index );
    950 }
    951 
    952 
    953 //===========================================================================================================================
    954 //	mDNSPlatformTCPSocket
    955 //===========================================================================================================================
    956 
    957 TCPSocket *
    958 mDNSPlatformTCPSocket
    959 	(
    960 	mDNS			* const m,
    961 	TCPSocketFlags		flags,
    962 	mDNSIPPort			*	port
    963 	)
    964 {
    965 	TCPSocket *		sock    = NULL;
    966 	u_long				on		= 1;  // "on" for setsockopt
    967 	struct sockaddr_in	saddr;
    968 	int					len;
    969 	mStatus				err		= mStatus_NoError;
    970 
    971 	DEBUG_UNUSED( m );
    972 
    973 	require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
    974 
    975 	// Setup connection data object
    976 
    977 	sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
    978 	require_action( sock, exit, err = mStatus_NoMemoryErr );
    979 	mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
    980 	sock->fd		= INVALID_SOCKET;
    981 	sock->flags		= flags;
    982 	sock->m			= m;
    983 
    984 	mDNSPlatformMemZero(&saddr, sizeof(saddr));
    985 	saddr.sin_family		= AF_INET;
    986 	saddr.sin_addr.s_addr	= htonl( INADDR_ANY );
    987 	saddr.sin_port			= port->NotAnInteger;
    988 
    989 	// Create the socket
    990 
    991 	sock->fd = socket(AF_INET, SOCK_STREAM, 0);
    992 	err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
    993 	require_noerr( err, exit );
    994 
    995 	// bind
    996 
    997 	err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr )  );
    998 	err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
    999 	require_noerr( err, exit );
   1000 
   1001 	// Set it to be non-blocking
   1002 
   1003 	err = ioctlsocket( sock->fd, FIONBIO, &on );
   1004 	err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
   1005 	require_noerr( err, exit );
   1006 
   1007 	// Get port number
   1008 
   1009 	mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
   1010 	len = sizeof( saddr );
   1011 
   1012 	err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
   1013 	err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
   1014 	require_noerr( err, exit );
   1015 
   1016 	port->NotAnInteger = saddr.sin_port;
   1017 
   1018 exit:
   1019 
   1020 	if ( err && sock )
   1021 	{
   1022 		TCPFreeSocket( sock );
   1023 		sock = mDNSNULL;
   1024 	}
   1025 
   1026 	return sock;
   1027 }
   1028 
   1029 //===========================================================================================================================
   1030 //	mDNSPlatformTCPConnect
   1031 //===========================================================================================================================
   1032 
   1033 mStatus
   1034 mDNSPlatformTCPConnect
   1035 	(
   1036 	TCPSocket			*	sock,
   1037 	const mDNSAddr		*	inDstIP,
   1038 	mDNSOpaque16 			inDstPort,
   1039 	domainname          *   hostname,
   1040 	mDNSInterfaceID			inInterfaceID,
   1041 	TCPConnectionCallback	inCallback,
   1042 	void *					inContext
   1043 	)
   1044 {
   1045 	struct sockaddr_in	saddr;
   1046 	mStatus				err		= mStatus_NoError;
   1047 
   1048 	DEBUG_UNUSED( inInterfaceID );
   1049 	( void ) hostname;
   1050 
   1051 	if ( inDstIP->type != mDNSAddrType_IPv4 )
   1052 	{
   1053 		LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
   1054 		return mStatus_UnknownErr;
   1055 	}
   1056 
   1057 	// Setup connection data object
   1058 
   1059 	sock->readEventHandler	= TCPCanRead;
   1060 	sock->userCallback		= inCallback;
   1061 	sock->userContext		= inContext;
   1062 
   1063 	mDNSPlatformMemZero(&saddr, sizeof(saddr));
   1064 	saddr.sin_family	= AF_INET;
   1065 	saddr.sin_port		= inDstPort.NotAnInteger;
   1066 	memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
   1067 
   1068 	// Try and do connect
   1069 
   1070 	err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
   1071 	require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
   1072 	sock->connected	= !err ? TRUE : FALSE;
   1073 
   1074 	if ( sock->connected )
   1075 	{
   1076 		err = TCPAddSocket( sock->m, sock );
   1077 		require_noerr( err, exit );
   1078 	}
   1079 	else
   1080 	{
   1081 		require_action( sock->m->p->registerWaitableEventFunc != NULL, exit, err = mStatus_ConnFailed );
   1082 
   1083 		sock->connectEvent	= CreateEvent( NULL, FALSE, FALSE, NULL );
   1084 		err = translate_errno( sock->connectEvent, GetLastError(), mStatus_UnknownErr );
   1085 		require_noerr( err, exit );
   1086 
   1087 		err = WSAEventSelect( sock->fd, sock->connectEvent, FD_CONNECT );
   1088 		require_noerr( err, exit );
   1089 
   1090 		err = sock->m->p->registerWaitableEventFunc( sock->m, sock->connectEvent, sock, TCPDidConnect );
   1091 		require_noerr( err, exit );
   1092 	}
   1093 
   1094 exit:
   1095 
   1096 	if ( !err )
   1097 	{
   1098 		err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
   1099 	}
   1100 
   1101 	return err;
   1102 }
   1103 
   1104 //===========================================================================================================================
   1105 //	mDNSPlatformTCPAccept
   1106 //===========================================================================================================================
   1107 
   1108 mDNSexport
   1109 mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
   1110 	{
   1111 	TCPSocket	*	sock = NULL;
   1112 	mStatus							err = mStatus_NoError;
   1113 
   1114 	require_action( !flags, exit, err = mStatus_UnsupportedErr );
   1115 
   1116 	sock = malloc( sizeof( TCPSocket ) );
   1117 	require_action( sock, exit, err = mStatus_NoMemoryErr );
   1118 
   1119 	mDNSPlatformMemZero( sock, sizeof( *sock ) );
   1120 
   1121 	sock->fd	= fd;
   1122 	sock->flags = flags;
   1123 
   1124 exit:
   1125 
   1126 	if ( err && sock )
   1127 	{
   1128 		free( sock );
   1129 		sock = NULL;
   1130 	}
   1131 
   1132 	return sock;
   1133 	}
   1134 
   1135 
   1136 //===========================================================================================================================
   1137 //	mDNSPlatformTCPCloseConnection
   1138 //===========================================================================================================================
   1139 
   1140 mDNSexport void	mDNSPlatformTCPCloseConnection( TCPSocket *sock )
   1141 {
   1142 	check( sock );
   1143 
   1144 	if ( sock->connectEvent && sock->m->p->unregisterWaitableEventFunc )
   1145 	{
   1146 		sock->m->p->unregisterWaitableEventFunc( sock->m, sock->connectEvent );
   1147 	}
   1148 
   1149 	if ( sock->fd != INVALID_SOCKET )
   1150 	{
   1151 		TCPCloseSocket( sock );
   1152 
   1153 		QueueUserAPC( ( PAPCFUNC ) TCPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
   1154 	}
   1155 }
   1156 
   1157 
   1158 //===========================================================================================================================
   1159 //	mDNSPlatformReadTCP
   1160 //===========================================================================================================================
   1161 
   1162 mDNSexport long	mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
   1163 {
   1164 	unsigned long	bytesLeft;
   1165 	int				wsaError;
   1166 	long			ret;
   1167 
   1168 	*closed = sock->closed;
   1169 	wsaError = sock->lastError;
   1170 	ret = -1;
   1171 
   1172 	if ( *closed )
   1173 	{
   1174 		ret = 0;
   1175 	}
   1176 	else if ( sock->lastError == 0 )
   1177 	{
   1178 		// First check to see if we have any data left in our buffer
   1179 
   1180 		bytesLeft = ( DWORD ) ( sock->eptr - sock->bptr );
   1181 
   1182 		if ( bytesLeft )
   1183 		{
   1184 			unsigned long bytesToCopy = ( bytesLeft < inBufferSize ) ? bytesLeft : inBufferSize;
   1185 
   1186 			memcpy( inBuffer, sock->bptr, bytesToCopy );
   1187 			sock->bptr += bytesToCopy;
   1188 
   1189 			if ( !sock->overlapped.pending && ( sock->bptr == sock->eptr ) )
   1190 			{
   1191 				sock->bptr = sock->bbuf;
   1192 				sock->eptr = sock->bbuf;
   1193 			}
   1194 
   1195 			ret = bytesToCopy;
   1196 		}
   1197 		else
   1198 		{
   1199 			wsaError = WSAEWOULDBLOCK;
   1200 		}
   1201 	}
   1202 
   1203 	// Always set the last winsock error, so that we don't inadvertently use a previous one
   1204 
   1205 	WSASetLastError( wsaError );
   1206 
   1207 	return ret;
   1208 }
   1209 
   1210 
   1211 //===========================================================================================================================
   1212 //	mDNSPlatformWriteTCP
   1213 //===========================================================================================================================
   1214 
   1215 mDNSexport long	mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
   1216 {
   1217 	int			nsent;
   1218 	OSStatus	err;
   1219 
   1220 	nsent = send( sock->fd, inMsg, inMsgSize, 0 );
   1221 
   1222 	err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
   1223 	require_noerr( err, exit );
   1224 
   1225 	if ( nsent < 0)
   1226 	{
   1227 		nsent = 0;
   1228 	}
   1229 
   1230 exit:
   1231 
   1232 	return nsent;
   1233 }
   1234 
   1235 //===========================================================================================================================
   1236 //	mDNSPlatformTCPGetFD
   1237 //===========================================================================================================================
   1238 
   1239 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
   1240 {
   1241 	return ( int ) sock->fd;
   1242 }
   1243 
   1244 
   1245 //===========================================================================================================================
   1246 //	TCPAddConnection
   1247 //===========================================================================================================================
   1248 
   1249 mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock )
   1250 {
   1251 	mStatus err;
   1252 
   1253 	( void ) inMDNS;
   1254 
   1255 	sock->bptr	= sock->bbuf;
   1256 	sock->eptr	= sock->bbuf;
   1257 	sock->ebuf	= sock->bbuf + sizeof( sock->bbuf );
   1258 
   1259 	dlog( kDebugLevelChatty, DEBUG_NAME "adding TCPSocket 0x%x:%d\n", sock, sock->fd );
   1260 	err = TCPBeginRecv( sock );
   1261 	require_noerr( err, exit );
   1262 
   1263 exit:
   1264 
   1265 	return err;
   1266 }
   1267 
   1268 
   1269 //===========================================================================================================================
   1270 //	TCPDidConnect
   1271 //===========================================================================================================================
   1272 
   1273 mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context )
   1274 {
   1275 	TCPSocket * sock = ( TCPSocket* ) context;
   1276 	TCPConnectionCallback callback = NULL;
   1277 	WSANETWORKEVENTS sockEvent;
   1278 	int err = kNoErr;
   1279 
   1280 	if ( inMDNS->p->unregisterWaitableEventFunc )
   1281 	{
   1282 		inMDNS->p->unregisterWaitableEventFunc( inMDNS, event );
   1283 	}
   1284 
   1285 	if ( sock )
   1286 	{
   1287 		callback = ( TCPConnectionCallback ) sock->userCallback;
   1288 		err = WSAEnumNetworkEvents( sock->fd, sock->connectEvent, &sockEvent );
   1289 		require_noerr( err, exit );
   1290 		require_action( sockEvent.lNetworkEvents & FD_CONNECT, exit, err = mStatus_UnknownErr );
   1291 		require_action( sockEvent.iErrorCode[ FD_CONNECT_BIT ] == 0, exit, err = sockEvent.iErrorCode[ FD_CONNECT_BIT ] );
   1292 
   1293 		sock->connected	= mDNStrue;
   1294 
   1295 		if ( sock->fd != INVALID_SOCKET )
   1296 		{
   1297 			err = TCPAddSocket( sock->m, sock );
   1298 			require_noerr( err, exit );
   1299 		}
   1300 
   1301 		if ( callback )
   1302 		{
   1303 			callback( sock, sock->userContext, TRUE, 0 );
   1304 		}
   1305 	}
   1306 
   1307 exit:
   1308 
   1309 	if ( err && callback )
   1310 	{
   1311 		callback( sock, sock->userContext, TRUE, err );
   1312 	}
   1313 }
   1314 
   1315 
   1316 
   1317 //===========================================================================================================================
   1318 //	TCPCanRead
   1319 //===========================================================================================================================
   1320 
   1321 mDNSlocal void TCPCanRead( TCPSocket * sock )
   1322 {
   1323 	TCPConnectionCallback callback = ( TCPConnectionCallback ) sock->userCallback;
   1324 
   1325 	if ( callback )
   1326 	{
   1327 		callback( sock, sock->userContext, mDNSfalse, sock->lastError );
   1328 	}
   1329 }
   1330 
   1331 
   1332 //===========================================================================================================================
   1333 //	TCPBeginRecv
   1334 //===========================================================================================================================
   1335 
   1336 mDNSlocal mStatus TCPBeginRecv( TCPSocket * sock )
   1337 {
   1338 	DWORD	bytesReceived	= 0;
   1339 	DWORD	flags			= 0;
   1340 	mStatus err;
   1341 
   1342 	dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
   1343 
   1344 	check( !sock->overlapped.pending );
   1345 
   1346 	ZeroMemory( &sock->overlapped.data, sizeof( sock->overlapped.data ) );
   1347 	sock->overlapped.data.hEvent = sock;
   1348 
   1349 	sock->overlapped.wbuf.buf = ( char* ) sock->eptr;
   1350 	sock->overlapped.wbuf.len = ( ULONG) ( sock->ebuf - sock->eptr );
   1351 
   1352 	err = WSARecv( sock->fd, &sock->overlapped.wbuf, 1, &bytesReceived, &flags, &sock->overlapped.data, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) TCPEndRecv );
   1353 	err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), WSAGetLastError(), kUnknownErr );
   1354 	require_noerr( err, exit );
   1355 
   1356 	sock->overlapped.pending = TRUE;
   1357 
   1358 exit:
   1359 
   1360 	return err;
   1361 }
   1362 
   1363 
   1364 //===========================================================================================================================
   1365 //	TCPEndRecv
   1366 //===========================================================================================================================
   1367 
   1368 mDNSlocal void CALLBACK TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
   1369 {
   1370 	TCPSocket * sock;
   1371 
   1372 	( void ) flags;
   1373 
   1374 	dlog( kDebugLevelChatty, DEBUG_NAME "%s: error = %d, bytesTransferred = %d\n", __ROUTINE__, error, bytesTransferred );
   1375 	sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
   1376 	require_action( sock, exit, error = ( DWORD ) mStatus_BadStateErr );
   1377 	dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
   1378 	sock->overlapped.error				= error;
   1379 	sock->overlapped.bytesTransferred	= bytesTransferred;
   1380 	check( sock->overlapped.pending );
   1381 	sock->overlapped.pending			= FALSE;
   1382 
   1383 	// Queue this socket
   1384 
   1385 	AddToTail( &gTCPDispatchableSockets, sock );
   1386 
   1387 exit:
   1388 
   1389 	return;
   1390 }
   1391 
   1392 
   1393 
   1394 //===========================================================================================================================
   1395 //	mDNSPlatformUDPSocket
   1396 //===========================================================================================================================
   1397 
   1398 mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
   1399 {
   1400 	UDPSocket*	sock	= NULL;
   1401 	mDNSIPPort	port	= requestedport;
   1402 	mStatus		err		= mStatus_NoError;
   1403 	unsigned	i;
   1404 
   1405 	// Setup connection data object
   1406 
   1407 	sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
   1408 	require_action( sock, exit, err = mStatus_NoMemoryErr );
   1409 	memset( sock, 0, sizeof( UDPSocket ) );
   1410 
   1411 	// Create the socket
   1412 
   1413 	sock->fd					= INVALID_SOCKET;
   1414 	sock->recvMsgPtr			= m->p->unicastSock4.recvMsgPtr;
   1415 	sock->addr					= m->p->unicastSock4.addr;
   1416 	sock->ifd					= NULL;
   1417 	sock->overlapped.pending	= FALSE;
   1418 	sock->m						= m;
   1419 
   1420 	// Try at most 10000 times to get a unique random port
   1421 
   1422 	for (i=0; i<10000; i++)
   1423 	{
   1424 		struct sockaddr_in saddr;
   1425 
   1426 		saddr.sin_family		= AF_INET;
   1427 		saddr.sin_addr.s_addr	= 0;
   1428 
   1429 		// The kernel doesn't do cryptographically strong random port
   1430 		// allocation, so we do it ourselves here
   1431 
   1432         if (mDNSIPPortIsZero(requestedport))
   1433 		{
   1434 			port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
   1435 		}
   1436 
   1437 		saddr.sin_port = port.NotAnInteger;
   1438 
   1439         err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
   1440         if (!err) break;
   1441 	}
   1442 
   1443 	require_noerr( err, exit );
   1444 
   1445 	// Set the port
   1446 
   1447 	sock->port = port;
   1448 
   1449 	// Arm the completion routine
   1450 
   1451 	err = UDPBeginRecv( sock );
   1452 	require_noerr( err, exit );
   1453 
   1454 	// Bookkeeping
   1455 
   1456 	sock->next		= gUDPSockets;
   1457 	gUDPSockets		= sock;
   1458 	gUDPNumSockets++;
   1459 
   1460 exit:
   1461 
   1462 	if ( err && sock )
   1463 	{
   1464 		UDPFreeSocket( sock );
   1465 		sock = NULL;
   1466 	}
   1467 
   1468 	return sock;
   1469 }
   1470 
   1471 //===========================================================================================================================
   1472 //	mDNSPlatformUDPClose
   1473 //===========================================================================================================================
   1474 
   1475 mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
   1476 {
   1477 	UDPSocket	*	current  = gUDPSockets;
   1478 	UDPSocket	*	last = NULL;
   1479 
   1480 	while ( current )
   1481 	{
   1482 		if ( current == sock )
   1483 		{
   1484 			if ( last == NULL )
   1485 			{
   1486 				gUDPSockets = sock->next;
   1487 			}
   1488 			else
   1489 			{
   1490 				last->next = sock->next;
   1491 			}
   1492 
   1493 			// Alertable I/O is great, except not so much when it comes to closing
   1494 			// the socket.  Anything that has been previously queued for this socket
   1495 			// will stay in the queue after you close the socket.  This is problematic
   1496 			// for obvious reasons. So we'll attempt to workaround this by closing
   1497 			// the socket which will prevent any further queued packets and then not calling
   1498 			// UDPFreeSocket directly, but by queueing it using QueueUserAPC.  The queues
   1499 			// are FIFO, so that will execute *after* any other previous items in the queue
   1500 			//
   1501 			// UDPEndRecv will check if the socket is valid, and if not, it will ignore
   1502 			// the packet
   1503 
   1504 			UDPCloseSocket( sock );
   1505 
   1506 			QueueUserAPC( ( PAPCFUNC ) UDPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
   1507 
   1508 			gUDPNumSockets--;
   1509 
   1510 			break;
   1511 		}
   1512 
   1513 		last	= current;
   1514 		current	= current->next;
   1515 	}
   1516 }
   1517 
   1518 
   1519 //===========================================================================================================================
   1520 //	mDNSPlatformSendUDP
   1521 //===========================================================================================================================
   1522 
   1523 mDNSexport mStatus
   1524 	mDNSPlatformSendUDP(
   1525 		const mDNS * const			inMDNS,
   1526 		const void * const	        inMsg,
   1527 		const mDNSu8 * const		inMsgEnd,
   1528 		mDNSInterfaceID 			inInterfaceID,
   1529 		UDPSocket *					inSrcSocket,
   1530 		const mDNSAddr *			inDstIP,
   1531 		mDNSIPPort 					inDstPort )
   1532 {
   1533 	SOCKET						sendingsocket = INVALID_SOCKET;
   1534 	mStatus						err = mStatus_NoError;
   1535 	mDNSInterfaceData *			ifd = (mDNSInterfaceData*) inInterfaceID;
   1536 	struct sockaddr_storage		addr;
   1537 	int							n;
   1538 
   1539 	DEBUG_USE_ONLY( inMDNS );
   1540 
   1541 	n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
   1542 	check( inMDNS );
   1543 	check( inMsg );
   1544 	check( inMsgEnd );
   1545 	check( inDstIP );
   1546 
   1547 	dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
   1548 
   1549 	if( inDstIP->type == mDNSAddrType_IPv4 )
   1550 	{
   1551 		struct sockaddr_in *		sa4;
   1552 
   1553 		sa4						= (struct sockaddr_in *) &addr;
   1554 		sa4->sin_family			= AF_INET;
   1555 		sa4->sin_port			= inDstPort.NotAnInteger;
   1556 		sa4->sin_addr.s_addr	= inDstIP->ip.v4.NotAnInteger;
   1557 		sendingsocket           = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
   1558 
   1559 		if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
   1560 	}
   1561 	else if( inDstIP->type == mDNSAddrType_IPv6 )
   1562 	{
   1563 		struct sockaddr_in6 *		sa6;
   1564 
   1565 		sa6					= (struct sockaddr_in6 *) &addr;
   1566 		sa6->sin6_family	= AF_INET6;
   1567 		sa6->sin6_port		= inDstPort.NotAnInteger;
   1568 		sa6->sin6_flowinfo	= 0;
   1569 		sa6->sin6_addr		= *( (struct in6_addr *) &inDstIP->ip.v6 );
   1570 		sa6->sin6_scope_id	= 0;	// Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
   1571 		sendingsocket		= ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
   1572 	}
   1573 	else
   1574 	{
   1575 		dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
   1576 		err = mStatus_BadParamErr;
   1577 		goto exit;
   1578 	}
   1579 
   1580 	if (IsValidSocket(sendingsocket))
   1581 	{
   1582 		n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
   1583 		err = translate_errno( n > 0, errno_compat(), kWriteErr );
   1584 
   1585 		if ( err )
   1586 		{
   1587 			// Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
   1588 
   1589 			if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
   1590 			{
   1591 				err = mStatus_TransientErr;
   1592 			}
   1593 			else
   1594 			{
   1595 				require_noerr( err, exit );
   1596 			}
   1597 		}
   1598 	}
   1599 
   1600 exit:
   1601 	return( err );
   1602 }
   1603 
   1604 
   1605 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
   1606 	{
   1607 	DEBUG_UNUSED( m );
   1608 	DEBUG_UNUSED( InterfaceID );
   1609 	}
   1610 
   1611 //===========================================================================================================================
   1612 //	mDNSPlatformSendRawPacket
   1613 //===========================================================================================================================
   1614 
   1615 mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
   1616     {
   1617     DEBUG_UNUSED( m );
   1618 	DEBUG_UNUSED( allowSleep );
   1619 	DEBUG_UNUSED( reason );
   1620     }
   1621 
   1622 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
   1623 	{
   1624 	DEBUG_UNUSED( msg );
   1625 	DEBUG_UNUSED( end );
   1626 	DEBUG_UNUSED( InterfaceID );
   1627 	}
   1628 
   1629 mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
   1630 	{
   1631 	DEBUG_UNUSED( msg );
   1632 	DEBUG_UNUSED( end );
   1633 	DEBUG_UNUSED( InterfaceID );
   1634 	}
   1635 
   1636 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
   1637 	{
   1638 	DEBUG_UNUSED( m );
   1639 	DEBUG_UNUSED( tpa );
   1640 	DEBUG_UNUSED( tha );
   1641 	DEBUG_UNUSED( InterfaceID );
   1642 	}
   1643 
   1644 mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
   1645 	{
   1646 	dlog( kDebugLevelInfo, "%s\n", msg );
   1647 	}
   1648 
   1649 mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
   1650 	{
   1651 	extern mDNS mDNSStorage;
   1652 	int type;
   1653 
   1654 	DEBUG_UNUSED( ident );
   1655 
   1656 	type = EVENTLOG_ERROR_TYPE;
   1657 
   1658 	switch (loglevel)
   1659 	{
   1660 		case MDNS_LOG_MSG:       type = EVENTLOG_ERROR_TYPE;		break;
   1661 		case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE;		break;
   1662 		case MDNS_LOG_SPS:       type = EVENTLOG_INFORMATION_TYPE;  break;
   1663 		case MDNS_LOG_INFO:      type = EVENTLOG_INFORMATION_TYPE;	break;
   1664 		case MDNS_LOG_DEBUG:     type = EVENTLOG_INFORMATION_TYPE;	break;
   1665 		default:
   1666 			fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
   1667 			fflush(stderr);
   1668 			}
   1669 
   1670 	mDNSStorage.p->reportStatusFunc( type, msg );
   1671 	dlog( kDebugLevelInfo, "%s\n", msg );
   1672 	}
   1673 
   1674 mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
   1675 	{
   1676 	DEBUG_UNUSED( src );
   1677 	DEBUG_UNUSED( dst );
   1678 	}
   1679 
   1680 //===========================================================================================================================
   1681 //	mDNSPlatformTLSSetupCerts
   1682 //===========================================================================================================================
   1683 
   1684 mDNSexport mStatus
   1685 mDNSPlatformTLSSetupCerts(void)
   1686 {
   1687 	return mStatus_UnsupportedErr;
   1688 }
   1689 
   1690 //===========================================================================================================================
   1691 //	mDNSPlatformTLSTearDownCerts
   1692 //===========================================================================================================================
   1693 
   1694 mDNSexport void
   1695 mDNSPlatformTLSTearDownCerts(void)
   1696 {
   1697 }
   1698 
   1699 //===========================================================================================================================
   1700 //	mDNSPlatformSetDNSConfig
   1701 //===========================================================================================================================
   1702 
   1703 mDNSlocal void SetDNSServers( mDNS *const m );
   1704 mDNSlocal void SetSearchDomainList( void );
   1705 
   1706 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains)
   1707 {
   1708 	if (setservers) SetDNSServers(m);
   1709 	if (setsearch) SetSearchDomainList();
   1710 
   1711 	if ( fqdn )
   1712 	{
   1713 		GetDDNSFQDN( fqdn );
   1714 	}
   1715 
   1716 	if ( browseDomains )
   1717 	{
   1718 		GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
   1719 	}
   1720 
   1721 	if ( regDomains )
   1722 	{
   1723 		GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
   1724 	}
   1725 }
   1726 
   1727 
   1728 //===========================================================================================================================
   1729 //	mDNSPlatformDynDNSHostNameStatusChanged
   1730 //===========================================================================================================================
   1731 
   1732 mDNSexport void
   1733 mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
   1734 {
   1735 	char		uname[MAX_ESCAPED_DOMAIN_NAME];
   1736 	BYTE		bStatus;
   1737 	LPCTSTR		name;
   1738 	HKEY		key = NULL;
   1739 	mStatus		err;
   1740 	char	*	p;
   1741 
   1742 	ConvertDomainNameToCString(dname, uname);
   1743 
   1744 	p = uname;
   1745 
   1746 	while (*p)
   1747 	{
   1748 		*p = (char) tolower(*p);
   1749 		if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
   1750 		p++;
   1751 	}
   1752 
   1753 	check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
   1754 	name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
   1755 	err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
   1756 	require_noerr( err, exit );
   1757 
   1758 	bStatus = ( status ) ? 0 : 1;
   1759 	err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
   1760 	require_noerr( err, exit );
   1761 
   1762 exit:
   1763 
   1764 	if ( key )
   1765 	{
   1766 		RegCloseKey( key );
   1767 	}
   1768 
   1769 	return;
   1770 }
   1771 
   1772 
   1773 mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
   1774     {
   1775     (void)m;  // unused
   1776     (void)rr;
   1777     (void)result;
   1778     }
   1779 
   1780 
   1781 
   1782 //===========================================================================================================================
   1783 //	SetDomainSecrets
   1784 //===========================================================================================================================
   1785 
   1786 // This routine needs to be called whenever the system secrets database changes.
   1787 // We call it from DynDNSConfigDidChange and mDNSPlatformInit
   1788 
   1789 void
   1790 SetDomainSecrets( mDNS * const m )
   1791 {
   1792 	DomainAuthInfo *ptr;
   1793 	domainname		fqdn;
   1794 	DNameListElem * regDomains = NULL;
   1795 
   1796 	// Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
   1797 	// In the case where the user simultaneously removes their DDNS host name and the key
   1798 	// for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
   1799 	// server before it loses access to the necessary key. Otherwise, we'd leave orphaned
   1800 	// address records behind that we no longer have permission to delete.
   1801 
   1802 	for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
   1803 		ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
   1804 
   1805 	GetDDNSFQDN( &fqdn );
   1806 
   1807 	if ( fqdn.c[ 0 ] )
   1808 	{
   1809 		SetDomainSecret( m, &fqdn );
   1810 	}
   1811 
   1812 	GetDDNSDomains( &regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
   1813 
   1814 	while ( regDomains )
   1815 	{
   1816 		DNameListElem * current = regDomains;
   1817 		SetDomainSecret( m, &current->name );
   1818 		regDomains = regDomains->next;
   1819 		free( current );
   1820 	}
   1821 }
   1822 
   1823 
   1824 //===========================================================================================================================
   1825 //	SetSearchDomainList
   1826 //===========================================================================================================================
   1827 
   1828 mDNSlocal void SetDomainFromDHCP( void );
   1829 mDNSlocal void SetReverseMapSearchDomainList( void );
   1830 
   1831 mDNSlocal void
   1832 SetSearchDomainList( void )
   1833 {
   1834 	char			*	searchList	= NULL;
   1835 	DWORD				searchListLen;
   1836 	//DNameListElem	*	head = NULL;
   1837 	//DNameListElem	*	current = NULL;
   1838 	char			*	tok;
   1839 	HKEY				key;
   1840 	mStatus				err;
   1841 
   1842 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
   1843 	require_noerr( err, exit );
   1844 
   1845 	err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
   1846 	require_noerr( err, exit );
   1847 
   1848 	// Windows separates the search domains with ','
   1849 
   1850 	tok = strtok( searchList, "," );
   1851 	while ( tok )
   1852 	{
   1853 		if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
   1854 			mDNS_AddSearchDomain_CString(tok, mDNSNULL);
   1855 		tok = strtok( NULL, "," );
   1856 	}
   1857 
   1858 exit:
   1859 
   1860 	if ( searchList )
   1861 	{
   1862 		free( searchList );
   1863 	}
   1864 
   1865 	if ( key )
   1866 	{
   1867 		RegCloseKey( key );
   1868 	}
   1869 
   1870 	SetDomainFromDHCP();
   1871 	SetReverseMapSearchDomainList();
   1872 }
   1873 
   1874 
   1875 //===========================================================================================================================
   1876 //	SetReverseMapSearchDomainList
   1877 //===========================================================================================================================
   1878 
   1879 mDNSlocal void
   1880 SetReverseMapSearchDomainList( void )
   1881 {
   1882 	struct ifaddrs	*	ifa;
   1883 
   1884 	ifa = myGetIfAddrs( 1 );
   1885 	while (ifa)
   1886 	{
   1887 		mDNSAddr addr;
   1888 
   1889 		if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
   1890 		{
   1891 			mDNSAddr	netmask;
   1892 			char		buffer[256];
   1893 
   1894 			if (!SetupAddr(&netmask, ifa->ifa_netmask))
   1895 			{
   1896 				sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
   1897                                                              addr.ip.v4.b[2] & netmask.ip.v4.b[2],
   1898                                                              addr.ip.v4.b[1] & netmask.ip.v4.b[1],
   1899                                                              addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
   1900 				mDNS_AddSearchDomain_CString(buffer, mDNSNULL);
   1901 			}
   1902 		}
   1903 
   1904 		ifa = ifa->ifa_next;
   1905 	}
   1906 
   1907 	return;
   1908 }
   1909 
   1910 
   1911 //===========================================================================================================================
   1912 //	SetDNSServers
   1913 //===========================================================================================================================
   1914 
   1915 mDNSlocal void
   1916 SetDNSServers( mDNS *const m )
   1917 {
   1918 	PIP_PER_ADAPTER_INFO	pAdapterInfo	=	NULL;
   1919 	FIXED_INFO			*	fixedInfo	= NULL;
   1920 	ULONG					bufLen		= 0;
   1921 	IP_ADDR_STRING		*	dnsServerList;
   1922 	IP_ADDR_STRING		*	ipAddr;
   1923 	DWORD					index;
   1924 	int						i			= 0;
   1925 	mStatus					err			= kUnknownErr;
   1926 
   1927 	// Get the primary interface.
   1928 
   1929 	index = GetPrimaryInterface();
   1930 
   1931 	// This should have the interface index of the primary index.  Fall back in cases where
   1932 	// it can't be determined.
   1933 
   1934 	if ( index )
   1935 	{
   1936 		bufLen = 0;
   1937 
   1938 		for ( i = 0; i < 100; i++ )
   1939 		{
   1940 			err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
   1941 
   1942 			if ( err != ERROR_BUFFER_OVERFLOW )
   1943 			{
   1944 				break;
   1945 			}
   1946 
   1947 			pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
   1948 			require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
   1949 		}
   1950 
   1951 		require_noerr( err, exit );
   1952 
   1953 		dnsServerList = &pAdapterInfo->DnsServerList;
   1954 	}
   1955 	else
   1956 	{
   1957 		bufLen = sizeof( FIXED_INFO );
   1958 
   1959 		for ( i = 0; i < 100; i++ )
   1960 		{
   1961 			if ( fixedInfo )
   1962 			{
   1963 				GlobalFree( fixedInfo );
   1964 				fixedInfo = NULL;
   1965 			}
   1966 
   1967 			fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
   1968 			require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
   1969 
   1970 			err = GetNetworkParams( fixedInfo, &bufLen );
   1971 
   1972 			if ( err != ERROR_BUFFER_OVERFLOW )
   1973 			{
   1974 				break;
   1975 			}
   1976 		}
   1977 
   1978 		require_noerr( err, exit );
   1979 
   1980 		dnsServerList = &fixedInfo->DnsServerList;
   1981 	}
   1982 
   1983 	for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
   1984 	{
   1985 		mDNSAddr addr;
   1986 		err = StringToAddress( &addr, ipAddr->IpAddress.String );
   1987 		if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort, mDNSfalse, 0);
   1988 	}
   1989 
   1990 exit:
   1991 
   1992 	if ( pAdapterInfo )
   1993 	{
   1994 		free( pAdapterInfo );
   1995 	}
   1996 
   1997 	if ( fixedInfo )
   1998 	{
   1999 		GlobalFree( fixedInfo );
   2000 	}
   2001 }
   2002 
   2003 
   2004 //===========================================================================================================================
   2005 //	SetDomainFromDHCP
   2006 //===========================================================================================================================
   2007 
   2008 mDNSlocal void
   2009 SetDomainFromDHCP( void )
   2010 {
   2011 	int					i			= 0;
   2012 	IP_ADAPTER_INFO *	pAdapterInfo;
   2013 	IP_ADAPTER_INFO *	pAdapter;
   2014 	DWORD				bufLen;
   2015 	DWORD				index;
   2016 	HKEY				key = NULL;
   2017 	LPSTR				domain = NULL;
   2018 	DWORD				dwSize;
   2019 	mStatus				err = mStatus_NoError;
   2020 
   2021 	pAdapterInfo	= NULL;
   2022 
   2023 	for ( i = 0; i < 100; i++ )
   2024 	{
   2025 		err = GetAdaptersInfo( pAdapterInfo, &bufLen);
   2026 
   2027 		if ( err != ERROR_BUFFER_OVERFLOW )
   2028 		{
   2029 			break;
   2030 		}
   2031 
   2032 		pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
   2033 		require_action( pAdapterInfo, exit, err = kNoMemoryErr );
   2034 	}
   2035 
   2036 	require_noerr( err, exit );
   2037 
   2038 	index = GetPrimaryInterface();
   2039 
   2040 	for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
   2041 	{
   2042 		if ( pAdapter->IpAddressList.IpAddress.String &&
   2043 		     pAdapter->IpAddressList.IpAddress.String[0] &&
   2044 		     pAdapter->GatewayList.IpAddress.String &&
   2045 		     pAdapter->GatewayList.IpAddress.String[0] &&
   2046 		     ( !index || ( pAdapter->Index == index ) ) )
   2047 		{
   2048 			// Found one that will work
   2049 
   2050 			char keyName[1024];
   2051 
   2052 			_snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
   2053 
   2054 			err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
   2055 			require_noerr( err, exit );
   2056 
   2057 			err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
   2058 			check_noerr( err );
   2059 
   2060 			if ( !domain || !domain[0] )
   2061 			{
   2062 				if ( domain )
   2063 				{
   2064 					free( domain );
   2065 					domain = NULL;
   2066 				}
   2067 
   2068 				err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
   2069 				check_noerr( err );
   2070 			}
   2071 
   2072 			if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain, mDNSNULL);
   2073 
   2074 			break;
   2075 		}
   2076 	}
   2077 
   2078 exit:
   2079 
   2080 	if ( pAdapterInfo )
   2081 	{
   2082 		free( pAdapterInfo );
   2083 	}
   2084 
   2085 	if ( domain )
   2086 	{
   2087 		free( domain );
   2088 	}
   2089 
   2090 	if ( key )
   2091 	{
   2092 		RegCloseKey( key );
   2093 	}
   2094 }
   2095 
   2096 
   2097 //===========================================================================================================================
   2098 //	mDNSPlatformGetPrimaryInterface
   2099 //===========================================================================================================================
   2100 
   2101 mDNSexport mStatus
   2102 mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
   2103 {
   2104 	IP_ADAPTER_INFO *	pAdapterInfo;
   2105 	IP_ADAPTER_INFO *	pAdapter;
   2106 	DWORD				bufLen;
   2107 	int					i;
   2108 	BOOL				found;
   2109 	DWORD				index;
   2110 	mStatus				err = mStatus_NoError;
   2111 
   2112 	DEBUG_UNUSED( m );
   2113 
   2114 	*v6 = zeroAddr;
   2115 
   2116 	pAdapterInfo	= NULL;
   2117 	bufLen			= 0;
   2118 	found			= FALSE;
   2119 
   2120 	for ( i = 0; i < 100; i++ )
   2121 	{
   2122 		err = GetAdaptersInfo( pAdapterInfo, &bufLen);
   2123 
   2124 		if ( err != ERROR_BUFFER_OVERFLOW )
   2125 		{
   2126 			break;
   2127 		}
   2128 
   2129 		pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
   2130 		require_action( pAdapterInfo, exit, err = kNoMemoryErr );
   2131 	}
   2132 
   2133 	require_noerr( err, exit );
   2134 
   2135 	index = GetPrimaryInterface();
   2136 
   2137 	for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
   2138 	{
   2139 		if ( pAdapter->IpAddressList.IpAddress.String &&
   2140 		     pAdapter->IpAddressList.IpAddress.String[0] &&
   2141 		     pAdapter->GatewayList.IpAddress.String &&
   2142 		     pAdapter->GatewayList.IpAddress.String[0] &&
   2143 		     ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
   2144 		     ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
   2145 		     ( !index || ( pAdapter->Index == index ) ) )
   2146 		{
   2147 			// Found one that will work
   2148 
   2149 			if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
   2150 			{
   2151 				memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
   2152 			}
   2153 
   2154 			found = TRUE;
   2155 			break;
   2156 		}
   2157 	}
   2158 
   2159 exit:
   2160 
   2161 	if ( pAdapterInfo )
   2162 	{
   2163 		free( pAdapterInfo );
   2164 	}
   2165 
   2166 	return err;
   2167 }
   2168 
   2169 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
   2170 	{
   2171 	(void) m;
   2172 	(void) InterfaceID;
   2173 	(void) EthAddr;
   2174 	(void) IPAddr;
   2175 	(void) iteration;
   2176 	}
   2177 
   2178 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
   2179 	{
   2180 	(void) rr;
   2181 	(void) intf;
   2182 
   2183 	return 1;
   2184 	}
   2185 
   2186 
   2187 #if 0
   2188 #pragma mark -
   2189 #endif
   2190 
   2191 //===========================================================================================================================
   2192 //	debugf_
   2193 //===========================================================================================================================
   2194 #if( MDNS_DEBUGMSGS )
   2195 mDNSexport void	debugf_( const char *inFormat, ... )
   2196 {
   2197 	char		buffer[ 512 ];
   2198     va_list		args;
   2199     mDNSu32		length;
   2200 
   2201 	va_start( args, inFormat );
   2202 	length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
   2203 	va_end( args );
   2204 
   2205 	dlog( kDebugLevelInfo, "%s\n", buffer );
   2206 }
   2207 #endif
   2208 
   2209 //===========================================================================================================================
   2210 //	verbosedebugf_
   2211 //===========================================================================================================================
   2212 
   2213 #if( MDNS_DEBUGMSGS > 1 )
   2214 mDNSexport void	verbosedebugf_( const char *inFormat, ... )
   2215 {
   2216 	char		buffer[ 512 ];
   2217     va_list		args;
   2218     mDNSu32		length;
   2219 
   2220 	va_start( args, inFormat );
   2221 	length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
   2222 	va_end( args );
   2223 
   2224 	dlog( kDebugLevelVerbose, "%s\n", buffer );
   2225 }
   2226 #endif
   2227 
   2228 
   2229 #if 0
   2230 #pragma mark -
   2231 #pragma mark == Platform Internals  ==
   2232 #endif
   2233 
   2234 
   2235 //===========================================================================================================================
   2236 //	SetupNiceName
   2237 //===========================================================================================================================
   2238 
   2239 mStatus	SetupNiceName( mDNS * const inMDNS )
   2240 {
   2241 	HKEY		descKey = NULL;
   2242 	char		utf8[ 256 ];
   2243 	LPCTSTR		s;
   2244 	LPWSTR		joinName;
   2245 	NETSETUP_JOIN_STATUS joinStatus;
   2246 	mStatus		err = 0;
   2247 	DWORD		namelen;
   2248 	BOOL		ok;
   2249 
   2250 	check( inMDNS );
   2251 
   2252 	// Set up the nice name.
   2253 	utf8[0] = '\0';
   2254 
   2255 	// First try and open the registry key that contains the computer description value
   2256 	s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
   2257 	err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
   2258 	check_translated_errno( err == 0, errno_compat(), kNameErr );
   2259 
   2260 	if ( !err )
   2261 	{
   2262 		TCHAR	desc[256];
   2263 		DWORD	descSize = sizeof( desc );
   2264 
   2265 		// look for the computer description
   2266 		err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
   2267 
   2268 		if ( !err )
   2269 		{
   2270 			err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
   2271 		}
   2272 
   2273 		if ( err )
   2274 		{
   2275 			utf8[ 0 ] = '\0';
   2276 		}
   2277 	}
   2278 
   2279 	// if we can't find it in the registry, then use the hostname of the machine
   2280 	if ( err || ( utf8[ 0 ] == '\0' ) )
   2281 	{
   2282 		TCHAR hostname[256];
   2283 
   2284 		namelen = sizeof( hostname ) / sizeof( TCHAR );
   2285 
   2286 		ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
   2287 		err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
   2288 		check_noerr( err );
   2289 
   2290 		if( !err )
   2291 		{
   2292 			err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
   2293 		}
   2294 
   2295 		if ( err )
   2296 		{
   2297 			utf8[ 0 ] = '\0';
   2298 		}
   2299 	}
   2300 
   2301 	// if we can't get the hostname
   2302 	if ( err || ( utf8[ 0 ] == '\0' ) )
   2303 	{
   2304 		// Invalidate name so fall back to a default name.
   2305 
   2306 		strcpy( utf8, kMDNSDefaultName );
   2307 	}
   2308 
   2309 	utf8[ sizeof( utf8 ) - 1 ]	= '\0';
   2310 	inMDNS->nicelabel.c[ 0 ]	= (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
   2311 	memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
   2312 
   2313 	dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
   2314 
   2315 	if ( descKey )
   2316 	{
   2317 		RegCloseKey( descKey );
   2318 	}
   2319 
   2320 	ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
   2321 	ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
   2322 
   2323 	namelen = sizeof( inMDNS->p->nbname );
   2324 	ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
   2325 	check( ok );
   2326 	if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
   2327 
   2328 	err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
   2329 	check ( err == NERR_Success );
   2330 	if ( err == NERR_Success )
   2331 	{
   2332 		if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
   2333 		{
   2334 			err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
   2335 			check( !err );
   2336 			if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
   2337 		}
   2338 
   2339 		NetApiBufferFree( joinName );
   2340 		joinName = NULL;
   2341 	}
   2342 
   2343 	err = 0;
   2344 
   2345 	return( err );
   2346 }
   2347 
   2348 //===========================================================================================================================
   2349 //	SetupHostName
   2350 //===========================================================================================================================
   2351 
   2352 mDNSlocal mStatus	SetupHostName( mDNS * const inMDNS )
   2353 {
   2354 	mStatus		err = 0;
   2355 	char		tempString[ 256 ];
   2356 	DWORD		tempStringLen;
   2357 	domainlabel tempLabel;
   2358 	BOOL		ok;
   2359 
   2360 	check( inMDNS );
   2361 
   2362 	// Set up the nice name.
   2363 	tempString[ 0 ] = '\0';
   2364 
   2365 	// use the hostname of the machine
   2366 	tempStringLen = sizeof( tempString );
   2367 	ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
   2368 	err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
   2369 	check_noerr( err );
   2370 
   2371 	// if we can't get the hostname
   2372 	if( err || ( tempString[ 0 ] == '\0' ) )
   2373 	{
   2374 		// Invalidate name so fall back to a default name.
   2375 
   2376 		strcpy( tempString, kMDNSDefaultName );
   2377 	}
   2378 
   2379 	tempString[ sizeof( tempString ) - 1 ] = '\0';
   2380 	tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
   2381 	memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
   2382 
   2383 	// Set up the host name.
   2384 
   2385 	ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
   2386 	if( inMDNS->hostlabel.c[ 0 ] == 0 )
   2387 	{
   2388 		// Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
   2389 
   2390 		MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
   2391 	}
   2392 
   2393 	check( inMDNS->hostlabel.c[ 0 ] != 0 );
   2394 
   2395 	mDNS_SetFQDN( inMDNS );
   2396 
   2397 	dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
   2398 
   2399 	return( err );
   2400 }
   2401 
   2402 //===========================================================================================================================
   2403 //	SetupName
   2404 //===========================================================================================================================
   2405 
   2406 mDNSlocal mStatus	SetupName( mDNS * const inMDNS )
   2407 {
   2408 	mStatus		err = 0;
   2409 
   2410 	check( inMDNS );
   2411 
   2412 	err = SetupNiceName( inMDNS );
   2413 	check_noerr( err );
   2414 
   2415 	err = SetupHostName( inMDNS );
   2416 	check_noerr( err );
   2417 
   2418 	return err;
   2419 }
   2420 
   2421 
   2422 //===========================================================================================================================
   2423 //	SetupInterfaceList
   2424 //===========================================================================================================================
   2425 
   2426 mStatus	SetupInterfaceList( mDNS * const inMDNS )
   2427 {
   2428 	mStatus						err;
   2429 	mDNSInterfaceData **		next;
   2430 	mDNSInterfaceData *			ifd;
   2431 	struct ifaddrs *			addrs;
   2432 	struct ifaddrs *			p;
   2433 	struct ifaddrs *			loopbackv4;
   2434 	struct ifaddrs *			loopbackv6;
   2435 	u_int						flagMask;
   2436 	u_int						flagTest;
   2437 	mDNSBool					foundv4;
   2438 	mDNSBool					foundv6;
   2439 	mDNSBool					foundUnicastSock4DestAddr;
   2440 	mDNSBool					foundUnicastSock6DestAddr;
   2441 
   2442 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
   2443 	check( inMDNS );
   2444 	check( inMDNS->p );
   2445 
   2446 	inMDNS->p->registeredLoopback4	= mDNSfalse;
   2447 	inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
   2448 	addrs							= NULL;
   2449 	foundv4							= mDNSfalse;
   2450 	foundv6							= mDNSfalse;
   2451 	foundUnicastSock4DestAddr		= mDNSfalse;
   2452 	foundUnicastSock6DestAddr		= mDNSfalse;
   2453 
   2454 	// Tear down any existing interfaces that may be set up.
   2455 
   2456 	TearDownInterfaceList( inMDNS );
   2457 
   2458 	// Set up the name of this machine.
   2459 
   2460 	err = SetupName( inMDNS );
   2461 	check_noerr( err );
   2462 
   2463 	// Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
   2464 	// can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
   2465 
   2466 	err = getifaddrs( &addrs );
   2467 	require_noerr( err, exit );
   2468 
   2469 	loopbackv4	= NULL;
   2470 	loopbackv6	= NULL;
   2471 	next		= &inMDNS->p->interfaceList;
   2472 
   2473 	flagMask = IFF_UP | IFF_MULTICAST;
   2474 	flagTest = IFF_UP | IFF_MULTICAST;
   2475 
   2476 #if( MDNS_WINDOWS_ENABLE_IPV4 )
   2477 	for( p = addrs; p; p = p->ifa_next )
   2478 	{
   2479 		if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
   2480 		{
   2481 			continue;
   2482 		}
   2483 		if( p->ifa_flags & IFF_LOOPBACK )
   2484 		{
   2485 			if( !loopbackv4 )
   2486 			{
   2487 				loopbackv4 = p;
   2488 			}
   2489 			continue;
   2490 		}
   2491 		dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
   2492 			p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
   2493 
   2494 		err = SetupInterface( inMDNS, p, &ifd );
   2495 		require_noerr( err, exit );
   2496 
   2497 		// If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
   2498 		// register him, but we also want to note that we haven't found a v4 interface
   2499 		// so that we register loopback so same host operations work
   2500 
   2501 		if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
   2502 		{
   2503 			foundv4 = mDNStrue;
   2504 		}
   2505 
   2506 		if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
   2507 		{
   2508 			inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
   2509 		}
   2510 
   2511 		// If we're on a platform that doesn't have WSARecvMsg(), there's no way
   2512 		// of determing the destination address of a packet that is sent to us.
   2513 		// For multicast packets, that's easy to determine.  But for the unicast
   2514 		// sockets, we'll fake it by taking the address of the first interface
   2515 		// that is successfully setup.
   2516 
   2517 		if ( !foundUnicastSock4DestAddr )
   2518 		{
   2519 			inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
   2520 			foundUnicastSock4DestAddr = TRUE;
   2521 		}
   2522 
   2523 		*next = ifd;
   2524 		next  = &ifd->next;
   2525 		++inMDNS->p->interfaceCount;
   2526 	}
   2527 #endif
   2528 
   2529 	// Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
   2530 
   2531 #if( MDNS_WINDOWS_ENABLE_IPV6 )
   2532 	for( p = addrs; p; p = p->ifa_next )
   2533 	{
   2534 		if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
   2535 		{
   2536 			continue;
   2537 		}
   2538 		if( p->ifa_flags & IFF_LOOPBACK )
   2539 		{
   2540 			if( !loopbackv6 )
   2541 			{
   2542 				loopbackv6 = p;
   2543 			}
   2544 			continue;
   2545 		}
   2546 		dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
   2547 			p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
   2548 
   2549 		err = SetupInterface( inMDNS, p, &ifd );
   2550 		require_noerr( err, exit );
   2551 
   2552 		// If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
   2553 		// register him, but we also want to note that we haven't found a v4 interface
   2554 		// so that we register loopback so same host operations work
   2555 
   2556 		if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
   2557 		{
   2558 			foundv6 = mDNStrue;
   2559 		}
   2560 
   2561 		// If we're on a platform that doesn't have WSARecvMsg(), there's no way
   2562 		// of determing the destination address of a packet that is sent to us.
   2563 		// For multicast packets, that's easy to determine.  But for the unicast
   2564 		// sockets, we'll fake it by taking the address of the first interface
   2565 		// that is successfully setup.
   2566 
   2567 		if ( !foundUnicastSock6DestAddr )
   2568 		{
   2569 			inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
   2570 			foundUnicastSock6DestAddr = TRUE;
   2571 		}
   2572 
   2573 		*next = ifd;
   2574 		next  = &ifd->next;
   2575 		++inMDNS->p->interfaceCount;
   2576 	}
   2577 #endif
   2578 
   2579 	// If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
   2580 
   2581 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
   2582 
   2583 	flagMask |= IFF_LOOPBACK;
   2584 	flagTest |= IFF_LOOPBACK;
   2585 
   2586 	for( p = addrs; p; p = p->ifa_next )
   2587 	{
   2588 		if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
   2589 		{
   2590 			continue;
   2591 		}
   2592 		if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
   2593 		{
   2594 			continue;
   2595 		}
   2596 
   2597 		v4loopback = p;
   2598 		break;
   2599 	}
   2600 
   2601 #endif
   2602 
   2603 	if ( !foundv4 && loopbackv4 )
   2604 	{
   2605 		dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
   2606 			loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
   2607 
   2608 		err = SetupInterface( inMDNS, loopbackv4, &ifd );
   2609 		require_noerr( err, exit );
   2610 
   2611 		inMDNS->p->registeredLoopback4 = mDNStrue;
   2612 
   2613 #if( MDNS_WINDOWS_ENABLE_IPV4 )
   2614 
   2615 		// If we're on a platform that doesn't have WSARecvMsg(), there's no way
   2616 		// of determing the destination address of a packet that is sent to us.
   2617 		// For multicast packets, that's easy to determine.  But for the unicast
   2618 		// sockets, we'll fake it by taking the address of the first interface
   2619 		// that is successfully setup.
   2620 
   2621 		if ( !foundUnicastSock4DestAddr )
   2622 		{
   2623 			inMDNS->p->unicastSock4.addr = ifd->sock.addr;
   2624 			foundUnicastSock4DestAddr = TRUE;
   2625 		}
   2626 #endif
   2627 
   2628 		*next = ifd;
   2629 		next  = &ifd->next;
   2630 		++inMDNS->p->interfaceCount;
   2631 	}
   2632 
   2633 	if ( !foundv6 && loopbackv6 )
   2634 	{
   2635 		dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
   2636 			loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
   2637 
   2638 		err = SetupInterface( inMDNS, loopbackv6, &ifd );
   2639 		require_noerr( err, exit );
   2640 
   2641 #if( MDNS_WINDOWS_ENABLE_IPV6 )
   2642 
   2643 		// If we're on a platform that doesn't have WSARecvMsg(), there's no way
   2644 		// of determing the destination address of a packet that is sent to us.
   2645 		// For multicast packets, that's easy to determine.  But for the unicast
   2646 		// sockets, we'll fake it by taking the address of the first interface
   2647 		// that is successfully setup.
   2648 
   2649 		if ( !foundUnicastSock6DestAddr )
   2650 		{
   2651 			inMDNS->p->unicastSock6.addr = ifd->sock.addr;
   2652 			foundUnicastSock6DestAddr = TRUE;
   2653 		}
   2654 #endif
   2655 
   2656 		*next = ifd;
   2657 		next  = &ifd->next;
   2658 		++inMDNS->p->interfaceCount;
   2659 	}
   2660 
   2661 	CheckFileShares( inMDNS );
   2662 
   2663 exit:
   2664 	if( err )
   2665 	{
   2666 		TearDownInterfaceList( inMDNS );
   2667 	}
   2668 	if( addrs )
   2669 	{
   2670 		freeifaddrs( addrs );
   2671 	}
   2672 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
   2673 	return( err );
   2674 }
   2675 
   2676 //===========================================================================================================================
   2677 //	TearDownInterfaceList
   2678 //===========================================================================================================================
   2679 
   2680 mStatus	TearDownInterfaceList( mDNS * const inMDNS )
   2681 {
   2682 	mDNSInterfaceData **		p;
   2683 	mDNSInterfaceData *		ifd;
   2684 
   2685 	dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
   2686 	check( inMDNS );
   2687 	check( inMDNS->p );
   2688 
   2689 	// Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
   2690 	// Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
   2691 	// so that remove events that occur after an interface goes away can still report the correct interface.
   2692 
   2693 	p = &inMDNS->p->inactiveInterfaceList;
   2694 	while( *p )
   2695 	{
   2696 		ifd = *p;
   2697 		if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
   2698 		{
   2699 			p = &ifd->next;
   2700 			continue;
   2701 		}
   2702 
   2703 		dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
   2704 		*p = ifd->next;
   2705 
   2706 		QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
   2707 	}
   2708 
   2709 	// Tear down all the interfaces.
   2710 
   2711 	while( inMDNS->p->interfaceList )
   2712 	{
   2713 		ifd = inMDNS->p->interfaceList;
   2714 		inMDNS->p->interfaceList = ifd->next;
   2715 
   2716 		TearDownInterface( inMDNS, ifd );
   2717 	}
   2718 	inMDNS->p->interfaceCount = 0;
   2719 
   2720 	dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
   2721 	return( mStatus_NoError );
   2722 }
   2723 
   2724 //===========================================================================================================================
   2725 //	SetupInterface
   2726 //===========================================================================================================================
   2727 
   2728 mDNSlocal mStatus	SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
   2729 {
   2730 	mDNSInterfaceData	*	ifd;
   2731 	mDNSInterfaceData	*	p;
   2732 	mStatus					err;
   2733 
   2734 	ifd = NULL;
   2735 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
   2736 	check( inMDNS );
   2737 	check( inMDNS->p );
   2738 	check( inIFA );
   2739 	check( inIFA->ifa_addr );
   2740 	check( outIFD );
   2741 
   2742 	// Allocate memory for the interface and initialize it.
   2743 
   2744 	ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
   2745 	require_action( ifd, exit, err = mStatus_NoMemoryErr );
   2746 	ifd->sock.fd		= kInvalidSocketRef;
   2747 	ifd->sock.overlapped.pending = FALSE;
   2748 	ifd->sock.ifd		= ifd;
   2749 	ifd->sock.next		= NULL;
   2750 	ifd->sock.m			= inMDNS;
   2751 	ifd->index			= inIFA->ifa_extra.index;
   2752 	ifd->scopeID		= inIFA->ifa_extra.index;
   2753 	check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
   2754 	strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
   2755 	ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
   2756 
   2757 	strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
   2758 	ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
   2759 
   2760 	// We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
   2761 	// that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
   2762 	// on a large configured network, which means there's a good chance that most or all the other devices on that
   2763 	// network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
   2764 	// but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
   2765 	// devices on a large configured network, so we are willing to make that sacrifice.
   2766 
   2767 	ifd->interfaceInfo.McastTxRx   = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
   2768 	ifd->interfaceInfo.InterfaceID = NULL;
   2769 
   2770 	for( p = inMDNS->p->interfaceList; p; p = p->next )
   2771 	{
   2772 		if ( strcmp( p->name, ifd->name ) == 0 )
   2773 		{
   2774 			if (!ifd->interfaceInfo.InterfaceID)
   2775 			{
   2776 				ifd->interfaceInfo.InterfaceID	= (mDNSInterfaceID) p;
   2777 			}
   2778 
   2779 			if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
   2780 			     ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
   2781 			     ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
   2782 			{
   2783 				ifd->interfaceInfo.McastTxRx = mDNSfalse;
   2784 			}
   2785 
   2786 			break;
   2787 		}
   2788 	}
   2789 
   2790 	if ( !ifd->interfaceInfo.InterfaceID )
   2791 	{
   2792 		ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
   2793 	}
   2794 
   2795 	// Set up a socket for this interface (if needed).
   2796 
   2797 	if( ifd->interfaceInfo.McastTxRx )
   2798 	{
   2799 		DWORD size;
   2800 
   2801 		err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
   2802 		require_noerr( err, exit );
   2803 		ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
   2804 		ifd->sock.port = MulticastDNSPort;
   2805 
   2806 		// Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
   2807 
   2808 		err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
   2809 
   2810 		if ( err )
   2811 		{
   2812 			ifd->sock.recvMsgPtr = NULL;
   2813 		}
   2814 	}
   2815 
   2816 	if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
   2817 	{
   2818 		inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
   2819 	}
   2820 
   2821 	ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
   2822 
   2823 	// Register this interface with mDNS.
   2824 
   2825 	err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
   2826 	require_noerr( err, exit );
   2827 
   2828 	err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
   2829 	require_noerr( err, exit );
   2830 
   2831 	memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
   2832 
   2833 	ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
   2834 
   2835 	if ( ifd->sock.fd != kInvalidSocketRef )
   2836 	{
   2837 		err = UDPBeginRecv( &ifd->sock );
   2838 		require_noerr( err, exit );
   2839 	}
   2840 
   2841 	err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
   2842 	require_noerr( err, exit );
   2843 	ifd->hostRegistered = mDNStrue;
   2844 
   2845 	dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
   2846 
   2847 	// Success!
   2848 
   2849 	*outIFD = ifd;
   2850 	ifd = NULL;
   2851 
   2852 exit:
   2853 
   2854 	if( ifd )
   2855 	{
   2856 		TearDownInterface( inMDNS, ifd );
   2857 	}
   2858 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
   2859 	return( err );
   2860 }
   2861 
   2862 //===========================================================================================================================
   2863 //	TearDownInterface
   2864 //===========================================================================================================================
   2865 
   2866 mDNSlocal mStatus	TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
   2867 {
   2868 	check( inMDNS );
   2869 	check( inIFD );
   2870 
   2871 	// Deregister this interface with mDNS.
   2872 
   2873 	dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
   2874 
   2875 	if( inIFD->hostRegistered )
   2876 	{
   2877 		inIFD->hostRegistered = mDNSfalse;
   2878 		mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
   2879 	}
   2880 
   2881 	// Tear down the multicast socket.
   2882 
   2883 	UDPCloseSocket( &inIFD->sock );
   2884 
   2885 	// If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
   2886 	// the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
   2887 
   2888 	if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
   2889 	{
   2890 		inIFD->next = inMDNS->p->inactiveInterfaceList;
   2891 		inMDNS->p->inactiveInterfaceList = inIFD;
   2892 		dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
   2893 	}
   2894 	else
   2895 	{
   2896 		dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
   2897 		QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
   2898 	}
   2899 
   2900 	return( mStatus_NoError );
   2901 }
   2902 
   2903 mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
   2904 {
   2905 	free( inIFD );
   2906 }
   2907 
   2908 //===========================================================================================================================
   2909 //	SetupSocket
   2910 //===========================================================================================================================
   2911 
   2912 mDNSlocal mStatus	SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  )
   2913 {
   2914 	mStatus			err;
   2915 	SocketRef		sock;
   2916 	int				option;
   2917 	DWORD			bytesReturned = 0;
   2918 	BOOL			behavior = FALSE;
   2919 
   2920 	DEBUG_UNUSED( inMDNS );
   2921 
   2922 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
   2923 	check( inMDNS );
   2924 	check( outSocketRef );
   2925 
   2926 	// Set up an IPv4 or IPv6 UDP socket.
   2927 
   2928 	sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
   2929 	err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
   2930 	require_noerr( err, exit );
   2931 
   2932 	// Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
   2933 	// if we're creating a multicast socket
   2934 
   2935 	if ( port.NotAnInteger )
   2936 	{
   2937 		option = 1;
   2938 		err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
   2939 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   2940 	}
   2941 
   2942 	// <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
   2943 	//
   2944 	// Not sure why, but the default behavior for sockets is to behave incorrectly
   2945 	// when using them in Overlapped I/O mode on XP. According to MSDN:
   2946 	//
   2947 	// SIO_UDP_CONNRESET (opcode setting: I, T==3)
   2948 	//     Windows XP:  Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
   2949 	//     Set to FALSE to disable reporting.
   2950 	//
   2951 	// Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
   2952 	// messages were being sent to us after we sent out packets to a multicast address. This is clearly
   2953 	// incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
   2954 	// will no longer receive any packets from that socket, which is not harmless. This behavior is only
   2955 	// seen on XP.
   2956 	//
   2957 	// So we turn off port unreachable reporting to make sure our sockets that are reading
   2958 	// multicast packets function correctly under all circumstances.
   2959 
   2960 	err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
   2961 	check_translated_errno( err == 0, errno_compat(), kOptionErr );
   2962 
   2963 	if( inAddr->sa_family == AF_INET )
   2964 	{
   2965 		mDNSv4Addr				ipv4;
   2966 		struct sockaddr_in		sa4;
   2967 		struct ip_mreq			mreqv4;
   2968 
   2969 		// Bind the socket to the desired port
   2970 
   2971 		ipv4.NotAnInteger 	= ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
   2972 		mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
   2973 		sa4.sin_family 		= AF_INET;
   2974 		sa4.sin_port 		= port.NotAnInteger;
   2975 		sa4.sin_addr.s_addr	= ipv4.NotAnInteger;
   2976 
   2977 		err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
   2978 		check_translated_errno( err == 0, errno_compat(), kUnknownErr );
   2979 
   2980 		// Turn on option to receive destination addresses and receiving interface.
   2981 
   2982 		option = 1;
   2983 		err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
   2984 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   2985 
   2986 		if (port.NotAnInteger)
   2987 		{
   2988 			// Join the all-DNS multicast group so we receive Multicast DNS packets
   2989 
   2990 			mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
   2991 			mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
   2992 			err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
   2993 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   2994 
   2995 			// Specify the interface to send multicast packets on this socket.
   2996 
   2997 			sa4.sin_addr.s_addr = ipv4.NotAnInteger;
   2998 			err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
   2999 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3000 
   3001 			// Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
   3002 
   3003 			option = 1;
   3004 			err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
   3005 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3006 		}
   3007 
   3008 		// Send unicast packets with TTL 255 (helps against spoofing).
   3009 
   3010 		option = 255;
   3011 		err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
   3012 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3013 
   3014 		// Send multicast packets with TTL 255 (helps against spoofing).
   3015 
   3016 		option = 255;
   3017 		err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
   3018 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3019 
   3020 	}
   3021 	else if( inAddr->sa_family == AF_INET6 )
   3022 	{
   3023 		struct sockaddr_in6 *		sa6p;
   3024 		struct sockaddr_in6			sa6;
   3025 		struct ipv6_mreq			mreqv6;
   3026 
   3027 		sa6p = (struct sockaddr_in6 *) inAddr;
   3028 
   3029 		// Bind the socket to the desired port
   3030 
   3031 		mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
   3032 		sa6.sin6_family		= AF_INET6;
   3033 		sa6.sin6_port		= port.NotAnInteger;
   3034 		sa6.sin6_flowinfo	= 0;
   3035 		sa6.sin6_addr		= sa6p->sin6_addr;
   3036 		sa6.sin6_scope_id	= sa6p->sin6_scope_id;
   3037 
   3038 		err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
   3039 		check_translated_errno( err == 0, errno_compat(), kUnknownErr );
   3040 
   3041 		// Turn on option to receive destination addresses and receiving interface.
   3042 
   3043 		option = 1;
   3044 		err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
   3045 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3046 
   3047 		// We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
   3048 		// for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
   3049 		// support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
   3050 
   3051 		#if( defined( IPV6_V6ONLY ) )
   3052 			option = 1;
   3053 			err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
   3054 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3055 		#endif
   3056 
   3057 		if ( port.NotAnInteger )
   3058 		{
   3059 			// Join the all-DNS multicast group so we receive Multicast DNS packets.
   3060 
   3061 			mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
   3062 			mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
   3063 			err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
   3064 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3065 
   3066 			// Specify the interface to send multicast packets on this socket.
   3067 
   3068 			option = (int) sa6p->sin6_scope_id;
   3069 			err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
   3070 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3071 
   3072 			// Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
   3073 
   3074 			option = 1;
   3075 			err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
   3076 			check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3077 		}
   3078 
   3079 		// Send unicast packets with TTL 255 (helps against spoofing).
   3080 
   3081 		option = 255;
   3082 		err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
   3083 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3084 
   3085 		// Send multicast packets with TTL 255 (helps against spoofing).
   3086 
   3087 		option = 255;
   3088 		err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
   3089 		check_translated_errno( err == 0, errno_compat(), kOptionErr );
   3090 	}
   3091 	else
   3092 	{
   3093 		dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
   3094 		err = kUnsupportedErr;
   3095 		goto exit;
   3096 	}
   3097 
   3098 	// Success!
   3099 
   3100 	*outSocketRef = sock;
   3101 	sock = kInvalidSocketRef;
   3102 	err = mStatus_NoError;
   3103 
   3104 exit:
   3105 	if( IsValidSocket( sock ) )
   3106 	{
   3107 		close_compat( sock );
   3108 	}
   3109 	return( err );
   3110 }
   3111 
   3112 //===========================================================================================================================
   3113 //	SetupSocket
   3114 //===========================================================================================================================
   3115 
   3116 mDNSlocal mStatus	SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
   3117 {
   3118 	mStatus		err;
   3119 
   3120 	check( inSA );
   3121 	check( outIP );
   3122 
   3123 	if( inSA->sa_family == AF_INET )
   3124 	{
   3125 		struct sockaddr_in *		sa4;
   3126 
   3127 		sa4 						= (struct sockaddr_in *) inSA;
   3128 		outIP->type 				= mDNSAddrType_IPv4;
   3129 		outIP->ip.v4.NotAnInteger	= sa4->sin_addr.s_addr;
   3130 		if( outPort )
   3131 		{
   3132 			outPort->NotAnInteger	= sa4->sin_port;
   3133 		}
   3134 		err = mStatus_NoError;
   3135 	}
   3136 	else if( inSA->sa_family == AF_INET6 )
   3137 	{
   3138 		struct sockaddr_in6 *		sa6;
   3139 
   3140 		sa6 			= (struct sockaddr_in6 *) inSA;
   3141 		outIP->type 	= mDNSAddrType_IPv6;
   3142 		outIP->ip.v6 	= *( (mDNSv6Addr *) &sa6->sin6_addr );
   3143 		if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
   3144 		{
   3145 			outIP->ip.v6.w[ 1 ] = 0;
   3146 		}
   3147 		if( outPort )
   3148 		{
   3149 			outPort->NotAnInteger = sa6->sin6_port;
   3150 		}
   3151 		err = mStatus_NoError;
   3152 	}
   3153 	else
   3154 	{
   3155 		dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
   3156 		err = mStatus_BadParamErr;
   3157 	}
   3158 	return( err );
   3159 }
   3160 
   3161 
   3162 #if 0
   3163 #pragma mark -
   3164 #endif
   3165 
   3166 //===========================================================================================================================
   3167 //	UDPBeginRecv
   3168 //===========================================================================================================================
   3169 
   3170 mDNSlocal OSStatus UDPBeginRecv( UDPSocket * sock )
   3171 {
   3172 	DWORD	size;
   3173 	DWORD	numTries;
   3174 	mStatus	err;
   3175 
   3176 	dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
   3177 
   3178 	require_action( sock != NULL, exit, err = mStatus_BadStateErr );
   3179 	check( !sock->overlapped.pending );
   3180 
   3181 	// Initialize the buffer structure
   3182 
   3183 	sock->overlapped.wbuf.buf	= (char *) &sock->packet;
   3184 	sock->overlapped.wbuf.len	= (u_long) sizeof( sock->packet );
   3185 	sock->srcAddrLen			= sizeof( sock->srcAddr );
   3186 
   3187 	// Initialize the overlapped structure
   3188 
   3189 	ZeroMemory( &sock->overlapped.data, sizeof( OVERLAPPED ) );
   3190 	sock->overlapped.data.hEvent = sock;
   3191 
   3192 	numTries = 0;
   3193 
   3194 	do
   3195 	{
   3196 		if ( sock->recvMsgPtr )
   3197 		{
   3198 			sock->wmsg.name				= ( LPSOCKADDR ) &sock->srcAddr;
   3199 			sock->wmsg.namelen			= sock->srcAddrLen;
   3200 			sock->wmsg.lpBuffers		= &sock->overlapped.wbuf;
   3201 			sock->wmsg.dwBufferCount	= 1;
   3202 			sock->wmsg.Control.buf		= ( CHAR* ) sock->controlBuffer;
   3203 			sock->wmsg.Control.len		= sizeof( sock->controlBuffer );
   3204 			sock->wmsg.dwFlags			= 0;
   3205 
   3206 			err = sock->recvMsgPtr( sock->fd, &sock->wmsg, &size, &sock->overlapped.data, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
   3207 			err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), (OSStatus) WSAGetLastError(), kUnknownErr );
   3208 
   3209 			// <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
   3210 			//
   3211 			// There seems to be a bug in some network device drivers that involves calling WSARecvMsg() in
   3212 			// overlapped i/o mode. Although all the parameters to WSARecvMsg() are correct, it returns a
   3213 			// WSAEFAULT error code when there is no actual error. We have found experientially that falling
   3214 			// back to using WSARecvFrom() when this happens will work correctly.
   3215 
   3216 			if ( err == WSAEFAULT ) sock->recvMsgPtr = NULL;
   3217 		}
   3218 		else
   3219 		{
   3220 			DWORD flags = 0;
   3221 
   3222 			err = WSARecvFrom( sock->fd, &sock->overlapped.wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sock->srcAddr, &sock->srcAddrLen, &sock->overlapped.data, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
   3223 			err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
   3224 		}
   3225 
   3226 		// According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
   3227 		//
   3228 		// "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
   3229 		//                 send operation resulted in an ICMP "Port Unreachable" message."
   3230 		//
   3231 		// Because this is the case, we want to ignore this error and try again.  Just in case
   3232 		// this is some kind of pathological condition, we'll break out of the retry loop
   3233 		// after 100 iterations
   3234 
   3235 		require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
   3236 	}
   3237 	while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
   3238 
   3239 	sock->overlapped.pending = TRUE;
   3240 
   3241 exit:
   3242 
   3243 	if ( err )
   3244 	{
   3245 		LogMsg( "WSARecvMsg failed (%d)\n", err );
   3246 	}
   3247 
   3248 	return err;
   3249 }
   3250 
   3251 
   3252 //===========================================================================================================================
   3253 //	UDPEndRecv
   3254 //===========================================================================================================================
   3255 
   3256 mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
   3257 {
   3258 	UDPSocket * sock = NULL;
   3259 
   3260 	( void ) flags;
   3261 
   3262 	dlog( kDebugLevelChatty, DEBUG_NAME "%s: err = %d, bytesTransferred = %d\n", __ROUTINE__, err, bytesTransferred );
   3263 	require_action_quiet( err != WSA_OPERATION_ABORTED, exit, err = ( DWORD ) kUnknownErr );
   3264 	require_noerr( err, exit );
   3265 	sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
   3266 	require_action( sock != NULL, exit, err = ( DWORD ) kUnknownErr );
   3267 	dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
   3268 	sock->overlapped.error				= err;
   3269 	sock->overlapped.bytesTransferred	= bytesTransferred;
   3270 	check( sock->overlapped.pending );
   3271 	sock->overlapped.pending			= FALSE;
   3272 
   3273 	// Translate the source of this packet into mDNS data types
   3274 
   3275 	SockAddrToMDNSAddr( (struct sockaddr *) &sock->srcAddr, &sock->overlapped.srcAddr, &sock->overlapped.srcPort );
   3276 
   3277 	// Initialize the destination of this packet. Just in case
   3278 	// we can't determine this info because we couldn't call
   3279 	// WSARecvMsg (recvMsgPtr)
   3280 
   3281 	sock->overlapped.dstAddr = sock->addr;
   3282 	sock->overlapped.dstPort = sock->port;
   3283 
   3284 	if ( sock->recvMsgPtr )
   3285 	{
   3286 		LPWSACMSGHDR	header;
   3287 		LPWSACMSGHDR	last = NULL;
   3288 		int				count = 0;
   3289 
   3290 		// Parse the control information. Reject packets received on the wrong interface.
   3291 
   3292 		// <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
   3293 		//
   3294 		// There seems to be an interaction between Bullguard and this next bit of code.
   3295 		// When a user's machine is running Bullguard, the control information that is
   3296 		// returned is corrupted, and the code would go into an infinite loop. We'll add
   3297 		// two bits of defensive coding here. The first will check that each pointer to
   3298 		// the LPWSACMSGHDR that is returned in the for loop is different than the last.
   3299 		// This fixes the problem with Bullguard. The second will break out of this loop
   3300 		// after 100 iterations, just in case the corruption isn't caught by the first
   3301 		// check.
   3302 
   3303 		for ( header = WSA_CMSG_FIRSTHDR( &sock->wmsg ); header; header = WSA_CMSG_NXTHDR( &sock->wmsg, header ) )
   3304 		{
   3305 			if ( ( header != last ) && ( ++count < 100 ) )
   3306 			{
   3307 				last = header;
   3308 
   3309 				if ( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
   3310 				{
   3311 					IN_PKTINFO * ipv4PacketInfo;
   3312 
   3313 					ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
   3314 
   3315 					if ( sock->ifd != NULL )
   3316 					{
   3317 						require_action( ipv4PacketInfo->ipi_ifindex == sock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
   3318 					}
   3319 
   3320 					sock->overlapped.dstAddr.type 				= mDNSAddrType_IPv4;
   3321 					sock->overlapped.dstAddr.ip.v4.NotAnInteger	= ipv4PacketInfo->ipi_addr.s_addr;
   3322 				}
   3323 				else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
   3324 				{
   3325 					IN6_PKTINFO * ipv6PacketInfo;
   3326 
   3327 					ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
   3328 
   3329 					if ( sock->ifd != NULL )
   3330 					{
   3331 						require_action( ipv6PacketInfo->ipi6_ifindex == ( sock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
   3332 					}
   3333 
   3334 					sock->overlapped.dstAddr.type	= mDNSAddrType_IPv6;
   3335 					sock->overlapped.dstAddr.ip.v6	= *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
   3336 				}
   3337 			}
   3338 			else
   3339 			{
   3340 				static BOOL loggedMessage = FALSE;
   3341 
   3342 				if ( !loggedMessage )
   3343 				{
   3344 					LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
   3345 					loggedMessage = TRUE;
   3346 				}
   3347 
   3348 				break;
   3349 			}
   3350 		}
   3351 	}
   3352 
   3353 	dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
   3354 	dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", bytesTransferred );
   3355 	dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %#a:%u\n", &sock->overlapped.srcAddr, ntohs( sock->overlapped.srcPort.NotAnInteger ) );
   3356 	dlog( kDebugLevelChatty, DEBUG_NAME "    dst       = %#a:%u\n", &sock->overlapped.dstAddr, ntohs( sock->overlapped.dstPort.NotAnInteger ) );
   3357 
   3358 	if ( sock->ifd != NULL )
   3359 	{
   3360 		dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &sock->ifd->interfaceInfo.ip, sock->ifd->index );
   3361 	}
   3362 
   3363 	dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
   3364 
   3365 	// Queue this socket
   3366 
   3367 	AddToTail( &gUDPDispatchableSockets, sock );
   3368 
   3369 exit:
   3370 
   3371 	return;
   3372 }
   3373 
   3374 
   3375 //===========================================================================================================================
   3376 //	InterfaceListDidChange
   3377 //===========================================================================================================================
   3378 void InterfaceListDidChange( mDNS * const inMDNS )
   3379 {
   3380 	mStatus err;
   3381 
   3382 	dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
   3383 	check( inMDNS );
   3384 
   3385 	// Tear down the existing interfaces and set up new ones using the new IP info.
   3386 
   3387 	err = TearDownInterfaceList( inMDNS );
   3388 	check_noerr( err );
   3389 
   3390 	err = SetupInterfaceList( inMDNS );
   3391 	check_noerr( err );
   3392 
   3393 	err = uDNS_SetupDNSConfig( inMDNS );
   3394 	check_noerr( err );
   3395 
   3396 	// Inform clients of the change.
   3397 
   3398 	mDNS_ConfigChanged(inMDNS);
   3399 
   3400 	// Force mDNS to update.
   3401 
   3402 	mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
   3403 }
   3404 
   3405 
   3406 //===========================================================================================================================
   3407 //	ComputerDescriptionDidChange
   3408 //===========================================================================================================================
   3409 void ComputerDescriptionDidChange( mDNS * const inMDNS )
   3410 {
   3411 	dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
   3412 	check( inMDNS );
   3413 
   3414 	// redo the names
   3415 	SetupNiceName( inMDNS );
   3416 }
   3417 
   3418 
   3419 //===========================================================================================================================
   3420 //	TCPIPConfigDidChange
   3421 //===========================================================================================================================
   3422 void TCPIPConfigDidChange( mDNS * const inMDNS )
   3423 {
   3424 	mStatus		err;
   3425 
   3426 	dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
   3427 	check( inMDNS );
   3428 
   3429 	err = uDNS_SetupDNSConfig( inMDNS );
   3430 	check_noerr( err );
   3431 }
   3432 
   3433 
   3434 //===========================================================================================================================
   3435 //	DynDNSConfigDidChange
   3436 //===========================================================================================================================
   3437 void DynDNSConfigDidChange( mDNS * const inMDNS )
   3438 {
   3439 	mStatus		err;
   3440 
   3441 	dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
   3442 	check( inMDNS );
   3443 
   3444 	SetDomainSecrets( inMDNS );
   3445 
   3446 	err = uDNS_SetupDNSConfig( inMDNS );
   3447 	check_noerr( err );
   3448 }
   3449 
   3450 
   3451 //===========================================================================================================================
   3452 //	FileSharingDidChange
   3453 //===========================================================================================================================
   3454 void FileSharingDidChange( mDNS * const inMDNS )
   3455 {
   3456 	dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
   3457 	check( inMDNS );
   3458 
   3459 	CheckFileShares( inMDNS );
   3460 }
   3461 
   3462 
   3463 //===========================================================================================================================
   3464 //	FilewallDidChange
   3465 //===========================================================================================================================
   3466 void FirewallDidChange( mDNS * const inMDNS )
   3467 {
   3468 	dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
   3469 	check( inMDNS );
   3470 
   3471 	CheckFileShares( inMDNS );
   3472 }
   3473 
   3474 
   3475 #if 0
   3476 #pragma mark -
   3477 #pragma mark == Utilities ==
   3478 #endif
   3479 
   3480 //===========================================================================================================================
   3481 //	getifaddrs
   3482 //===========================================================================================================================
   3483 
   3484 mDNSlocal int	getifaddrs( struct ifaddrs **outAddrs )
   3485 {
   3486 	int		err;
   3487 
   3488 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
   3489 
   3490 	// Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
   3491 	// XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
   3492 
   3493 	if( !gIPHelperLibraryInstance )
   3494 	{
   3495 		gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
   3496 		if( gIPHelperLibraryInstance )
   3497 		{
   3498 			gGetAdaptersAddressesFunctionPtr =
   3499 				(GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
   3500 			if( !gGetAdaptersAddressesFunctionPtr )
   3501 			{
   3502 				BOOL		ok;
   3503 
   3504 				ok = FreeLibrary( gIPHelperLibraryInstance );
   3505 				check_translated_errno( ok, GetLastError(), kUnknownErr );
   3506 				gIPHelperLibraryInstance = NULL;
   3507 			}
   3508 		}
   3509 	}
   3510 
   3511 	// Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
   3512 	// <rdar://problem/4278934>  Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
   3513 	// <rdar://problem/6145913>  Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
   3514 
   3515 	if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
   3516 	{
   3517 		err = getifaddrs_ipv4( outAddrs );
   3518 		require_noerr( err, exit );
   3519 	}
   3520 
   3521 #else
   3522 
   3523 	err = getifaddrs_ipv4( outAddrs );
   3524 	require_noerr( err, exit );
   3525 
   3526 #endif
   3527 
   3528 exit:
   3529 	return( err );
   3530 }
   3531 
   3532 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
   3533 //===========================================================================================================================
   3534 //	getifaddrs_ipv6
   3535 //===========================================================================================================================
   3536 
   3537 mDNSlocal int	getifaddrs_ipv6( struct ifaddrs **outAddrs )
   3538 {
   3539 	DWORD						err;
   3540 	int							i;
   3541 	DWORD						flags;
   3542 	struct ifaddrs *			head;
   3543 	struct ifaddrs **			next;
   3544 	IP_ADAPTER_ADDRESSES *		iaaList;
   3545 	ULONG						iaaListSize;
   3546 	IP_ADAPTER_ADDRESSES *		iaa;
   3547 	size_t						size;
   3548 	struct ifaddrs *			ifa;
   3549 
   3550 	check( gGetAdaptersAddressesFunctionPtr );
   3551 
   3552 	head	= NULL;
   3553 	next	= &head;
   3554 	iaaList	= NULL;
   3555 
   3556 	// Get the list of interfaces. The first call gets the size and the second call gets the actual data.
   3557 	// This loops to handle the case where the interface changes in the window after getting the size, but before the
   3558 	// second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
   3559 
   3560 	flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
   3561 	i = 0;
   3562 	for( ;; )
   3563 	{
   3564 		iaaListSize = 0;
   3565 		err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
   3566 		check( err == ERROR_BUFFER_OVERFLOW );
   3567 		check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
   3568 
   3569 		iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
   3570 		require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
   3571 
   3572 		err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
   3573 		if( err == ERROR_SUCCESS ) break;
   3574 
   3575 		free( iaaList );
   3576 		iaaList = NULL;
   3577 		++i;
   3578 		require( i < 100, exit );
   3579 		dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
   3580 	}
   3581 
   3582 	for( iaa = iaaList; iaa; iaa = iaa->Next )
   3583 	{
   3584 		int								addrIndex;
   3585 		IP_ADAPTER_UNICAST_ADDRESS	*	addr;
   3586 		DWORD							ipv6IfIndex;
   3587 		IP_ADAPTER_PREFIX			*	firstPrefix;
   3588 
   3589 		if( iaa->IfIndex > 0xFFFFFF )
   3590 		{
   3591 			dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
   3592 		}
   3593 		if( iaa->Ipv6IfIndex > 0xFF )
   3594 		{
   3595 			dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
   3596 		}
   3597 
   3598 		// For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
   3599 		// following code to crash when iterating through the prefix list.  This seems
   3600 		// to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
   3601 		// This shouldn't happen according to Microsoft docs which states:
   3602 		//
   3603 		//     "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
   3604 		//
   3605 		// So the data structure seems to be corrupted when we return from
   3606 		// GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
   3607 		// sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
   3608 		// modify iaa to have the correct values.
   3609 
   3610 		if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
   3611 		{
   3612 			ipv6IfIndex = iaa->Ipv6IfIndex;
   3613 			firstPrefix = iaa->FirstPrefix;
   3614 		}
   3615 		else
   3616 		{
   3617 			ipv6IfIndex	= 0;
   3618 			firstPrefix = NULL;
   3619 		}
   3620 
   3621 		// Skip pseudo and tunnel interfaces.
   3622 
   3623 		if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
   3624 		{
   3625 			continue;
   3626 		}
   3627 
   3628 		// Add each address as a separate interface to emulate the way getifaddrs works.
   3629 
   3630 		for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
   3631 		{
   3632 			int						family;
   3633 			int						prefixIndex;
   3634 			IP_ADAPTER_PREFIX *		prefix;
   3635 			ULONG					prefixLength;
   3636 			uint32_t				ipv4Index;
   3637 			struct sockaddr_in		ipv4Netmask;
   3638 
   3639 			family = addr->Address.lpSockaddr->sa_family;
   3640 			if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
   3641 
   3642 			// <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
   3643 			// Seems as if the problem here is a buggy implementation of some network interface
   3644 			// driver. It is reporting that is has a link-local address when it is actually
   3645 			// disconnected. This was causing a problem in AddressToIndexAndMask.
   3646 			// The solution is to call AddressToIndexAndMask first, and if unable to lookup
   3647 			// the address, to ignore that address.
   3648 
   3649 			ipv4Index = 0;
   3650 			memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
   3651 
   3652 			if ( family == AF_INET )
   3653 			{
   3654 				err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
   3655 
   3656 				if ( err )
   3657 				{
   3658 					err = 0;
   3659 					continue;
   3660 				}
   3661 			}
   3662 
   3663 			ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
   3664 			require_action( ifa, exit, err = WSAENOBUFS );
   3665 
   3666 			*next = ifa;
   3667 			next  = &ifa->ifa_next;
   3668 
   3669 			// Get the name.
   3670 
   3671 			size = strlen( iaa->AdapterName ) + 1;
   3672 			ifa->ifa_name = (char *) malloc( size );
   3673 			require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
   3674 			memcpy( ifa->ifa_name, iaa->AdapterName, size );
   3675 
   3676 			// Get interface flags.
   3677 
   3678 			ifa->ifa_flags = 0;
   3679 			if( iaa->OperStatus == IfOperStatusUp ) 		ifa->ifa_flags |= IFF_UP;
   3680 			if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK )	ifa->ifa_flags |= IFF_LOOPBACK;
   3681 			else if ( IsPointToPoint( addr ) )				ifa->ifa_flags |= IFF_POINTTOPOINT;
   3682 			if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) )	ifa->ifa_flags |= IFF_MULTICAST;
   3683 
   3684 
   3685 			// <rdar://problem/4045657> Interface index being returned is 512
   3686 			//
   3687 			// Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
   3688 			// This code used to shift the IPv4 index up to ensure uniqueness between
   3689 			// it and IPv6 indexes.  Although this worked, it was somewhat confusing to developers, who
   3690 			// then see interface indexes passed back that don't correspond to anything
   3691 			// that is seen in Win32 APIs or command line tools like "route".  As a relatively
   3692 			// small percentage of developers are actively using IPv6, it seems to
   3693 			// make sense to make our use of IPv4 as confusion free as possible.
   3694 			// So now, IPv6 interface indexes will be shifted up by a
   3695 			// constant value which will serve to uniquely identify them, and we will
   3696 			// leave IPv4 interface indexes unmodified.
   3697 
   3698 			switch( family )
   3699 			{
   3700 				case AF_INET:  ifa->ifa_extra.index = iaa->IfIndex; break;
   3701 				case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase;	 break;
   3702 				default: break;
   3703 			}
   3704 
   3705 			// Get lease lifetime
   3706 
   3707 			if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
   3708 			{
   3709 				ifa->ifa_dhcpEnabled		= TRUE;
   3710 				ifa->ifa_dhcpLeaseExpires	= time( NULL ) + addr->ValidLifetime;
   3711 			}
   3712 			else
   3713 			{
   3714 				ifa->ifa_dhcpEnabled		= FALSE;
   3715 				ifa->ifa_dhcpLeaseExpires	= 0;
   3716 			}
   3717 
   3718 			if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
   3719 			{
   3720 				memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
   3721 			}
   3722 
   3723 			// Because we don't get notified of womp changes, we're going to just assume
   3724 			// that all wired interfaces have it enabled. Before we go to sleep, we'll check
   3725 			// if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
   3726 			// accordingly
   3727 
   3728 			ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
   3729 
   3730 			// Get address.
   3731 
   3732 			switch( family )
   3733 			{
   3734 				case AF_INET:
   3735 				case AF_INET6:
   3736 					ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
   3737 					require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
   3738 					memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
   3739 					break;
   3740 
   3741 				default:
   3742 					break;
   3743 			}
   3744 			check( ifa->ifa_addr );
   3745 
   3746 			// Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
   3747 
   3748 			prefixLength = 0;
   3749 			for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next )
   3750 			{
   3751 				if( ( prefix->Address.lpSockaddr->sa_family == family ) && ( prefixIndex == addrIndex ) )
   3752 				{
   3753 					check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" );
   3754 					prefixLength = prefix->PrefixLength;
   3755 					break;
   3756 				}
   3757 			}
   3758 			switch( family )
   3759 			{
   3760 				case AF_INET:
   3761 				{
   3762 					struct sockaddr_in * sa4;
   3763 
   3764 					sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
   3765 					require_action( sa4, exit, err = WSAENOBUFS );
   3766 					sa4->sin_family = AF_INET;
   3767 					sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
   3768 
   3769 					dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
   3770 					ifa->ifa_netmask = (struct sockaddr *) sa4;
   3771 					break;
   3772 				}
   3773 
   3774 				case AF_INET6:
   3775 				{
   3776 					struct sockaddr_in6 *		sa6;
   3777 					int							len;
   3778 					int							maskIndex;
   3779 					uint8_t						maskByte;
   3780 
   3781 					require_action( prefixLength <= 128, exit, err = ERROR_INVALID_DATA );
   3782 
   3783 					sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
   3784 					require_action( sa6, exit, err = WSAENOBUFS );
   3785 					sa6->sin6_family = AF_INET6;
   3786 
   3787 					if( prefixLength == 0 )
   3788 					{
   3789 						dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__ );
   3790 						prefixLength = 128;
   3791 					}
   3792 					maskIndex = 0;
   3793 					for( len = (int) prefixLength; len > 0; len -= 8 )
   3794 					{
   3795 						if( len >= 8 ) maskByte = 0xFF;
   3796 						else		   maskByte = (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
   3797 						sa6->sin6_addr.s6_addr[ maskIndex++ ] = maskByte;
   3798 					}
   3799 					ifa->ifa_netmask = (struct sockaddr *) sa6;
   3800 					break;
   3801 				}
   3802 
   3803 				default:
   3804 					break;
   3805 			}
   3806 		}
   3807 	}
   3808 
   3809 	// Success!
   3810 
   3811 	if( outAddrs )
   3812 	{
   3813 		*outAddrs = head;
   3814 		head = NULL;
   3815 	}
   3816 	err = ERROR_SUCCESS;
   3817 
   3818 exit:
   3819 	if( head )
   3820 	{
   3821 		freeifaddrs( head );
   3822 	}
   3823 	if( iaaList )
   3824 	{
   3825 		free( iaaList );
   3826 	}
   3827 	return( (int) err );
   3828 }
   3829 
   3830 #endif	// MDNS_WINDOWS_USE_IPV6_IF_ADDRS
   3831 
   3832 //===========================================================================================================================
   3833 //	getifaddrs_ipv4
   3834 //===========================================================================================================================
   3835 
   3836 mDNSlocal int	getifaddrs_ipv4( struct ifaddrs **outAddrs )
   3837 {
   3838 	int						err;
   3839 	SOCKET					sock;
   3840 	DWORD					size;
   3841 	DWORD					actualSize;
   3842 	INTERFACE_INFO *		buffer;
   3843 	INTERFACE_INFO *		tempBuffer;
   3844 	INTERFACE_INFO *		ifInfo;
   3845 	int						n;
   3846 	int						i;
   3847 	struct ifaddrs *		head;
   3848 	struct ifaddrs **		next;
   3849 	struct ifaddrs *		ifa;
   3850 
   3851 	sock	= INVALID_SOCKET;
   3852 	buffer	= NULL;
   3853 	head	= NULL;
   3854 	next	= &head;
   3855 
   3856 	// Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
   3857 	// way to determine the size of the interface list beforehand, we have to start with an initial size guess and
   3858 	// call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
   3859 
   3860 	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
   3861 	err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
   3862 	require_noerr( err, exit );
   3863 
   3864 	n = 0;
   3865 	size = 16 * sizeof( INTERFACE_INFO );
   3866 	for( ;; )
   3867 	{
   3868 		tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
   3869 		require_action( tempBuffer, exit, err = WSAENOBUFS );
   3870 		buffer = tempBuffer;
   3871 
   3872 		err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
   3873 		if( err == 0 )
   3874 		{
   3875 			break;
   3876 		}
   3877 
   3878 		++n;
   3879 		require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
   3880 
   3881 		size += ( 16 * sizeof( INTERFACE_INFO ) );
   3882 	}
   3883 	check( actualSize <= size );
   3884 	check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
   3885 	n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
   3886 
   3887 	// Process the raw interface list and build a linked list of IPv4 interfaces.
   3888 
   3889 	for( i = 0; i < n; ++i )
   3890 	{
   3891 		uint32_t ifIndex;
   3892 		struct sockaddr_in netmask;
   3893 
   3894 		ifInfo = &buffer[ i ];
   3895 		if( ifInfo->iiAddress.Address.sa_family != AF_INET )
   3896 		{
   3897 			continue;
   3898 		}
   3899 
   3900 		// <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
   3901 		// See comment in getifaddrs_ipv6
   3902 
   3903 		ifIndex = 0;
   3904 		memset( &netmask, 0, sizeof( netmask ) );
   3905 		err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
   3906 
   3907 		if ( err )
   3908 		{
   3909 			continue;
   3910 		}
   3911 
   3912 		ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
   3913 		require_action( ifa, exit, err = WSAENOBUFS );
   3914 
   3915 		*next = ifa;
   3916 		next  = &ifa->ifa_next;
   3917 
   3918 		// Get the name.
   3919 
   3920 		ifa->ifa_name = (char *) malloc( 16 );
   3921 		require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
   3922 		sprintf( ifa->ifa_name, "%d", i + 1 );
   3923 
   3924 		// Get interface flags.
   3925 
   3926 		ifa->ifa_flags = (u_int) ifInfo->iiFlags;
   3927 
   3928 		// Get addresses.
   3929 
   3930 		if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
   3931 		{
   3932 			struct sockaddr_in *		sa4;
   3933 
   3934 			sa4 = &ifInfo->iiAddress.AddressIn;
   3935 			ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
   3936 			require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
   3937 			memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
   3938 
   3939 			ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
   3940 			require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
   3941 
   3942 			// <rdar://problem/4076478> Service won't start on Win2K. The address
   3943 			// family field was not being initialized.
   3944 
   3945 			ifa->ifa_netmask->sa_family = AF_INET;
   3946 			( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
   3947 			ifa->ifa_extra.index = ifIndex;
   3948 		}
   3949 		else
   3950 		{
   3951 			// Emulate an interface index.
   3952 
   3953 			ifa->ifa_extra.index = (uint32_t)( i + 1 );
   3954 		}
   3955 	}
   3956 
   3957 	// Success!
   3958 
   3959 	if( outAddrs )
   3960 	{
   3961 		*outAddrs = head;
   3962 		head = NULL;
   3963 	}
   3964 	err = 0;
   3965 
   3966 exit:
   3967 
   3968 	if( head )
   3969 	{
   3970 		freeifaddrs( head );
   3971 	}
   3972 	if( buffer )
   3973 	{
   3974 		free( buffer );
   3975 	}
   3976 	if( sock != INVALID_SOCKET )
   3977 	{
   3978 		closesocket( sock );
   3979 	}
   3980 	return( err );
   3981 }
   3982 
   3983 //===========================================================================================================================
   3984 //	freeifaddrs
   3985 //===========================================================================================================================
   3986 
   3987 mDNSlocal void	freeifaddrs( struct ifaddrs *inIFAs )
   3988 {
   3989 	struct ifaddrs *		p;
   3990 	struct ifaddrs *		q;
   3991 
   3992 	// Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
   3993 
   3994 	for( p = inIFAs; p; p = q )
   3995 	{
   3996 		q = p->ifa_next;
   3997 
   3998 		if( p->ifa_name )
   3999 		{
   4000 			free( p->ifa_name );
   4001 			p->ifa_name = NULL;
   4002 		}
   4003 		if( p->ifa_addr )
   4004 		{
   4005 			free( p->ifa_addr );
   4006 			p->ifa_addr = NULL;
   4007 		}
   4008 		if( p->ifa_netmask )
   4009 		{
   4010 			free( p->ifa_netmask );
   4011 			p->ifa_netmask = NULL;
   4012 		}
   4013 		if( p->ifa_broadaddr )
   4014 		{
   4015 			free( p->ifa_broadaddr );
   4016 			p->ifa_broadaddr = NULL;
   4017 		}
   4018 		if( p->ifa_dstaddr )
   4019 		{
   4020 			free( p->ifa_dstaddr );
   4021 			p->ifa_dstaddr = NULL;
   4022 		}
   4023 		if( p->ifa_data )
   4024 		{
   4025 			free( p->ifa_data );
   4026 			p->ifa_data = NULL;
   4027 		}
   4028 		free( p );
   4029 	}
   4030 }
   4031 
   4032 
   4033 //===========================================================================================================================
   4034 //	GetPrimaryInterface
   4035 //===========================================================================================================================
   4036 
   4037 mDNSlocal DWORD
   4038 GetPrimaryInterface()
   4039 {
   4040 	PMIB_IPFORWARDTABLE	pIpForwardTable	= NULL;
   4041 	DWORD				dwSize			= 0;
   4042 	BOOL				bOrder			= FALSE;
   4043 	OSStatus			err;
   4044 	DWORD				index			= 0;
   4045 	DWORD				metric			= 0;
   4046 	unsigned long int	i;
   4047 
   4048 	// Find out how big our buffer needs to be.
   4049 
   4050 	err = GetIpForwardTable(NULL, &dwSize, bOrder);
   4051 	require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
   4052 
   4053 	// Allocate the memory for the table
   4054 
   4055 	pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
   4056 	require_action( pIpForwardTable, exit, err = kNoMemoryErr );
   4057 
   4058 	// Now get the table.
   4059 
   4060 	err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
   4061 	require_noerr( err, exit );
   4062 
   4063 
   4064 	// Search for the row in the table we want.
   4065 
   4066 	for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
   4067 	{
   4068 		// Look for a default route
   4069 
   4070 		if ( pIpForwardTable->table[i].dwForwardDest == 0 )
   4071 		{
   4072 			if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
   4073 			{
   4074 				continue;
   4075 			}
   4076 
   4077 			index	= pIpForwardTable->table[i].dwForwardIfIndex;
   4078 			metric	= pIpForwardTable->table[i].dwForwardMetric1;
   4079 		}
   4080 	}
   4081 
   4082 exit:
   4083 
   4084 	if ( pIpForwardTable != NULL )
   4085 	{
   4086 		free( pIpForwardTable );
   4087 	}
   4088 
   4089 	return index;
   4090 }
   4091 
   4092 
   4093 //===========================================================================================================================
   4094 //	AddressToIndexAndMask
   4095 //===========================================================================================================================
   4096 
   4097 mDNSlocal mStatus
   4098 AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask  )
   4099 {
   4100 	// Before calling AddIPAddress we use GetIpAddrTable to get
   4101 	// an adapter to which we can add the IP.
   4102 
   4103 	PMIB_IPADDRTABLE	pIPAddrTable	= NULL;
   4104 	DWORD				dwSize			= 0;
   4105 	mStatus				err				= mStatus_UnknownErr;
   4106 	DWORD				i;
   4107 
   4108 	// For now, this is only for IPv4 addresses.  That is why we can safely cast
   4109 	// addr's to sockaddr_in.
   4110 
   4111 	require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
   4112 
   4113 	// Make an initial call to GetIpAddrTable to get the
   4114 	// necessary size into the dwSize variable
   4115 
   4116 	for ( i = 0; i < 100; i++ )
   4117 	{
   4118 		err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
   4119 
   4120 		if ( err != ERROR_INSUFFICIENT_BUFFER )
   4121 		{
   4122 			break;
   4123 		}
   4124 
   4125 		pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
   4126 		require_action( pIPAddrTable, exit, err = WSAENOBUFS );
   4127 	}
   4128 
   4129 	require_noerr( err, exit );
   4130 	err = mStatus_UnknownErr;
   4131 
   4132 	for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
   4133 	{
   4134 		if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
   4135 		{
   4136 			*ifIndex											= pIPAddrTable->table[i].dwIndex;
   4137 			( ( struct sockaddr_in*) mask )->sin_addr.s_addr	= pIPAddrTable->table[i].dwMask;
   4138 			err													= mStatus_NoError;
   4139 			break;
   4140 		}
   4141 	}
   4142 
   4143 exit:
   4144 
   4145 	if ( pIPAddrTable )
   4146 	{
   4147 		free( pIPAddrTable );
   4148 	}
   4149 
   4150 	return err;
   4151 }
   4152 
   4153 
   4154 //===========================================================================================================================
   4155 //	CanReceiveUnicast
   4156 //===========================================================================================================================
   4157 
   4158 mDNSlocal mDNSBool	CanReceiveUnicast( void )
   4159 {
   4160 	mDNSBool				ok;
   4161 	SocketRef				sock;
   4162 	struct sockaddr_in		addr;
   4163 
   4164 	// Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
   4165 
   4166 	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
   4167 	check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
   4168 	ok = IsValidSocket( sock );
   4169 	if( ok )
   4170 	{
   4171 		mDNSPlatformMemZero( &addr, sizeof( addr ) );
   4172 		addr.sin_family			= AF_INET;
   4173 		addr.sin_port			= MulticastDNSPort.NotAnInteger;
   4174 		addr.sin_addr.s_addr	= htonl( INADDR_ANY );
   4175 
   4176 		ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
   4177 		close_compat( sock );
   4178 	}
   4179 
   4180 	dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
   4181 	return( ok );
   4182 }
   4183 
   4184 
   4185 //===========================================================================================================================
   4186 //	IsPointToPoint
   4187 //===========================================================================================================================
   4188 
   4189 mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
   4190 {
   4191 	struct ifaddrs	*	addrs	=	NULL;
   4192 	struct ifaddrs	*	p		=	NULL;
   4193 	OSStatus			err;
   4194 	mDNSBool			ret		=	mDNSfalse;
   4195 
   4196 	// For now, only works for IPv4 interfaces
   4197 
   4198 	if ( addr->Address.lpSockaddr->sa_family == AF_INET )
   4199 	{
   4200 		// The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
   4201 
   4202 		err = getifaddrs_ipv4( &addrs );
   4203 		require_noerr( err, exit );
   4204 
   4205 		for ( p = addrs; p; p = p->ifa_next )
   4206 		{
   4207 			if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
   4208 			     ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
   4209 			{
   4210 				ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
   4211 				break;
   4212 			}
   4213 		}
   4214 	}
   4215 
   4216 exit:
   4217 
   4218 	if ( addrs )
   4219 	{
   4220 		freeifaddrs( addrs );
   4221 	}
   4222 
   4223 	return ret;
   4224 }
   4225 
   4226 
   4227 //===========================================================================================================================
   4228 //	GetWindowsVersionString
   4229 //===========================================================================================================================
   4230 
   4231 mDNSlocal OSStatus	GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
   4232 {
   4233 #if( !defined( VER_PLATFORM_WIN32_CE ) )
   4234 	#define VER_PLATFORM_WIN32_CE		3
   4235 #endif
   4236 
   4237 	OSStatus				err;
   4238 	OSVERSIONINFO			osInfo;
   4239 	BOOL					ok;
   4240 	const char *			versionString;
   4241 	DWORD					platformID;
   4242 	DWORD					majorVersion;
   4243 	DWORD					minorVersion;
   4244 	DWORD					buildNumber;
   4245 
   4246 	versionString = "unknown Windows version";
   4247 
   4248 	osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
   4249 	ok = GetVersionEx( &osInfo );
   4250 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
   4251 	require_noerr( err, exit );
   4252 
   4253 	platformID		= osInfo.dwPlatformId;
   4254 	majorVersion	= osInfo.dwMajorVersion;
   4255 	minorVersion	= osInfo.dwMinorVersion;
   4256 	buildNumber		= osInfo.dwBuildNumber & 0xFFFF;
   4257 
   4258 	if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
   4259 	{
   4260 		if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
   4261 		{
   4262 			versionString	= "Windows 95";
   4263 		}
   4264 		else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
   4265 		{
   4266 			versionString	= "Windows 95 SP1";
   4267 		}
   4268 		else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
   4269 		{
   4270 			versionString	= "Windows 95 OSR2";
   4271 		}
   4272 		else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
   4273 		{
   4274 			versionString	= "Windows 98";
   4275 		}
   4276 		else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
   4277 		{
   4278 			versionString	= "Windows 98 SP1";
   4279 		}
   4280 		else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
   4281 		{
   4282 			versionString	= "Windows 98 SE";
   4283 		}
   4284 		else if( minorVersion == 90 )
   4285 		{
   4286 			versionString	= "Windows ME";
   4287 		}
   4288 	}
   4289 	else if( platformID == VER_PLATFORM_WIN32_NT )
   4290 	{
   4291 		if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
   4292 		{
   4293 			versionString	= "Windows NT 3.51";
   4294 		}
   4295 		else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
   4296 		{
   4297 			versionString	= "Windows NT 4";
   4298 		}
   4299 		else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
   4300 		{
   4301 			versionString	= "Windows 2000";
   4302 		}
   4303 		else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
   4304 		{
   4305 			versionString	= "Windows XP";
   4306 		}
   4307 		else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
   4308 		{
   4309 			versionString	= "Windows Server 2003";
   4310 		}
   4311 	}
   4312 	else if( platformID == VER_PLATFORM_WIN32_CE )
   4313 	{
   4314 		versionString		= "Windows CE";
   4315 	}
   4316 
   4317 exit:
   4318 	if( inBuffer && ( inBufferSize > 0 ) )
   4319 	{
   4320 		inBufferSize -= 1;
   4321 		strncpy( inBuffer, versionString, inBufferSize );
   4322 		inBuffer[ inBufferSize ] = '\0';
   4323 	}
   4324 	return( err );
   4325 }
   4326 
   4327 
   4328 //===========================================================================================================================
   4329 //	RegQueryString
   4330 //===========================================================================================================================
   4331 
   4332 mDNSlocal mStatus
   4333 RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
   4334 {
   4335 	DWORD	type;
   4336 	int		i;
   4337 	mStatus err;
   4338 
   4339 	*stringLen	= MAX_ESCAPED_DOMAIN_NAME;
   4340 	*string		= NULL;
   4341 	i			= 0;
   4342 
   4343 	do
   4344 	{
   4345 		if ( *string )
   4346 		{
   4347 			free( *string );
   4348 		}
   4349 
   4350 		*string = (char*) malloc( *stringLen );
   4351 		require_action( *string, exit, err = mStatus_NoMemoryErr );
   4352 
   4353 		err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
   4354 
   4355 		i++;
   4356 	}
   4357 	while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
   4358 
   4359 	require_noerr_quiet( err, exit );
   4360 
   4361 	if ( enabled )
   4362 	{
   4363 		DWORD dwSize = sizeof( DWORD );
   4364 
   4365 		err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
   4366 		check_noerr( err );
   4367 
   4368 		err = kNoErr;
   4369 	}
   4370 
   4371 exit:
   4372 
   4373 	return err;
   4374 }
   4375 
   4376 
   4377 //===========================================================================================================================
   4378 //	StringToAddress
   4379 //===========================================================================================================================
   4380 
   4381 mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
   4382 {
   4383 	struct sockaddr_in6 sa6;
   4384 	struct sockaddr_in	sa4;
   4385 	INT					dwSize;
   4386 	mStatus				err;
   4387 
   4388 	sa6.sin6_family	= AF_INET6;
   4389 	dwSize			= sizeof( sa6 );
   4390 
   4391 	err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
   4392 
   4393 	if ( err == mStatus_NoError )
   4394 	{
   4395 		err = SetupAddr( ip, (struct sockaddr*) &sa6 );
   4396 		require_noerr( err, exit );
   4397 	}
   4398 	else
   4399 	{
   4400 		sa4.sin_family = AF_INET;
   4401 		dwSize = sizeof( sa4 );
   4402 
   4403 		err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
   4404 		err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
   4405 		require_noerr( err, exit );
   4406 
   4407 		err = SetupAddr( ip, (struct sockaddr*) &sa4 );
   4408 		require_noerr( err, exit );
   4409 	}
   4410 
   4411 exit:
   4412 
   4413 	return err;
   4414 }
   4415 
   4416 
   4417 //===========================================================================================================================
   4418 //	myGetIfAddrs
   4419 //===========================================================================================================================
   4420 
   4421 mDNSlocal struct ifaddrs*
   4422 myGetIfAddrs(int refresh)
   4423 {
   4424 	static struct ifaddrs *ifa = NULL;
   4425 
   4426 	if (refresh && ifa)
   4427 	{
   4428 		freeifaddrs(ifa);
   4429 		ifa = NULL;
   4430 	}
   4431 
   4432 	if (ifa == NULL)
   4433 	{
   4434 		getifaddrs(&ifa);
   4435 	}
   4436 
   4437 	return ifa;
   4438 }
   4439 
   4440 
   4441 //===========================================================================================================================
   4442 //	TCHARtoUTF8
   4443 //===========================================================================================================================
   4444 
   4445 mDNSlocal OSStatus
   4446 TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
   4447 {
   4448 #if( defined( UNICODE ) || defined( _UNICODE ) )
   4449 	OSStatus		err;
   4450 	int				len;
   4451 
   4452 	len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
   4453 	err = translate_errno( len > 0, errno_compat(), kUnknownErr );
   4454 	require_noerr( err, exit );
   4455 
   4456 exit:
   4457 	return( err );
   4458 #else
   4459 	return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
   4460 #endif
   4461 }
   4462 
   4463 
   4464 //===========================================================================================================================
   4465 //	WindowsLatin1toUTF8
   4466 //===========================================================================================================================
   4467 
   4468 mDNSlocal OSStatus
   4469 WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
   4470 {
   4471 	OSStatus		err;
   4472 	WCHAR *			utf16;
   4473 	int				len;
   4474 
   4475 	utf16 = NULL;
   4476 
   4477 	// Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
   4478 
   4479 	len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
   4480 	err = translate_errno( len > 0, errno_compat(), kUnknownErr );
   4481 	require_noerr( err, exit );
   4482 
   4483 	utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
   4484 	require_action( utf16, exit, err = kNoMemoryErr );
   4485 
   4486 	len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
   4487 	err = translate_errno( len > 0, errno_compat(), kUnknownErr );
   4488 	require_noerr( err, exit );
   4489 
   4490 	// Now convert the temporary UTF-16 to UTF-8.
   4491 
   4492 	len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
   4493 	err = translate_errno( len > 0, errno_compat(), kUnknownErr );
   4494 	require_noerr( err, exit );
   4495 
   4496 exit:
   4497 	if( utf16 ) free( utf16 );
   4498 	return( err );
   4499 }
   4500 
   4501 
   4502 //===========================================================================================================================
   4503 //	TCPCloseSocket
   4504 //===========================================================================================================================
   4505 
   4506 mDNSlocal void
   4507 TCPCloseSocket( TCPSocket * sock )
   4508 {
   4509 	dlog( kDebugLevelChatty, DEBUG_NAME "closing TCPSocket 0x%x:%d\n", sock, sock->fd );
   4510 
   4511 	RemoveFromList( &gTCPDispatchableSockets, sock );
   4512 
   4513 	if ( sock->fd != INVALID_SOCKET )
   4514 	{
   4515 		closesocket( sock->fd );
   4516 		sock->fd = INVALID_SOCKET;
   4517 	}
   4518 }
   4519 
   4520 
   4521 //===========================================================================================================================
   4522 //	TCPFreeSocket
   4523 //===========================================================================================================================
   4524 
   4525 mDNSlocal void CALLBACK
   4526 TCPFreeSocket( TCPSocket *sock )
   4527 {
   4528 	check( sock );
   4529 
   4530 	dlog( kDebugLevelChatty, DEBUG_NAME "freeing TCPSocket 0x%x:%d\n", sock, sock->fd );
   4531 
   4532 	if ( sock->connectEvent )
   4533 	{
   4534 		CloseHandle( sock->connectEvent );
   4535 		sock->connectEvent = NULL;
   4536 	}
   4537 
   4538 	if ( sock->fd != INVALID_SOCKET )
   4539 	{
   4540 		closesocket( sock->fd );
   4541 		sock->fd = INVALID_SOCKET;
   4542 	}
   4543 
   4544 	free( sock );
   4545 }
   4546 
   4547 
   4548 //===========================================================================================================================
   4549 //  UDPCloseSocket
   4550 //===========================================================================================================================
   4551 
   4552 mDNSlocal void
   4553 UDPCloseSocket( UDPSocket * sock )
   4554 {
   4555 	dlog( kDebugLevelChatty, DEBUG_NAME "closing UDPSocket %d\n", sock->fd );
   4556 
   4557 	RemoveFromList( &gUDPDispatchableSockets, sock );
   4558 
   4559 	if ( sock->fd != INVALID_SOCKET )
   4560 	{
   4561 		closesocket( sock->fd );
   4562 		sock->fd = INVALID_SOCKET;
   4563 	}
   4564 }
   4565 
   4566 
   4567 //===========================================================================================================================
   4568 //  UDPFreeSocket
   4569 //===========================================================================================================================
   4570 
   4571 mDNSlocal void CALLBACK
   4572 UDPFreeSocket( UDPSocket * sock )
   4573 {
   4574     check( sock );
   4575 
   4576 	dlog( kDebugLevelChatty, DEBUG_NAME "freeing UDPSocket %d\n", sock->fd );
   4577 
   4578     if ( sock->fd != INVALID_SOCKET )
   4579     {
   4580         closesocket( sock->fd );
   4581 		sock->fd = INVALID_SOCKET;
   4582     }
   4583 
   4584     free( sock );
   4585 }
   4586 
   4587 //===========================================================================================================================
   4588 //	SetupAddr
   4589 //===========================================================================================================================
   4590 
   4591 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
   4592 	{
   4593 	if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
   4594 
   4595 	if (sa->sa_family == AF_INET)
   4596 		{
   4597 		struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
   4598 		ip->type = mDNSAddrType_IPv4;
   4599 		ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
   4600 		return(mStatus_NoError);
   4601 		}
   4602 
   4603 	if (sa->sa_family == AF_INET6)
   4604 		{
   4605 		struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
   4606 		ip->type = mDNSAddrType_IPv6;
   4607 		if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
   4608 		ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
   4609 		return(mStatus_NoError);
   4610 		}
   4611 
   4612 	LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
   4613 	return(mStatus_Invalid);
   4614 	}
   4615 
   4616 
   4617 mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
   4618 {
   4619 	LPSTR		name = NULL;
   4620 	DWORD		dwSize;
   4621 	DWORD		enabled;
   4622 	HKEY		key = NULL;
   4623 	OSStatus	err;
   4624 
   4625 	check( fqdn );
   4626 
   4627 	// Initialize
   4628 
   4629 	fqdn->c[0] = '\0';
   4630 
   4631 	// Get info from Bonjour registry key
   4632 
   4633 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
   4634 	require_noerr( err, exit );
   4635 
   4636 	err = RegQueryString( key, "", &name, &dwSize, &enabled );
   4637 	if ( !err && ( name[0] != '\0' ) && enabled )
   4638 	{
   4639 		if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
   4640 		{
   4641 			dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
   4642 		}
   4643 	}
   4644 
   4645 exit:
   4646 
   4647 	if ( key )
   4648 	{
   4649 		RegCloseKey( key );
   4650 		key = NULL;
   4651 	}
   4652 
   4653 	if ( name )
   4654 	{
   4655 		free( name );
   4656 		name = NULL;
   4657 	}
   4658 }
   4659 
   4660 
   4661 #ifdef UNICODE
   4662 mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
   4663 #else
   4664 mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
   4665 #endif
   4666 {
   4667 	char		subKeyName[kRegistryMaxKeyLength + 1];
   4668 	DWORD		cSubKeys = 0;
   4669 	DWORD		cbMaxSubKey;
   4670 	DWORD		cchMaxClass;
   4671 	DWORD		dwSize;
   4672 	HKEY		key = NULL;
   4673 	HKEY		subKey = NULL;
   4674 	domainname	dname;
   4675 	DWORD		i;
   4676 	OSStatus	err;
   4677 
   4678 	check( domains );
   4679 
   4680 	// Initialize
   4681 
   4682 	*domains = NULL;
   4683 
   4684 	err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
   4685 	require_noerr( err, exit );
   4686 
   4687 	// Get information about this node
   4688 
   4689 	err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
   4690 	require_noerr( err, exit );
   4691 
   4692 	for ( i = 0; i < cSubKeys; i++)
   4693 	{
   4694 		DWORD enabled;
   4695 
   4696 		dwSize = kRegistryMaxKeyLength;
   4697 
   4698 		err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
   4699 
   4700 		if ( !err )
   4701 		{
   4702 			err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
   4703 			require_noerr( err, exit );
   4704 
   4705 			dwSize = sizeof( DWORD );
   4706 			err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
   4707 
   4708 			if ( !err && ( subKeyName[0] != '\0' ) && enabled )
   4709 			{
   4710 				if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
   4711 				{
   4712 					dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
   4713 				}
   4714 				else
   4715 				{
   4716 					DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
   4717 					require_action( domain, exit, err = mStatus_NoMemoryErr );
   4718 
   4719 					AssignDomainName(&domain->name, &dname);
   4720 					domain->next = *domains;
   4721 
   4722 					*domains = domain;
   4723 				}
   4724 			}
   4725 
   4726 			RegCloseKey( subKey );
   4727 			subKey = NULL;
   4728 		}
   4729 	}
   4730 
   4731 exit:
   4732 
   4733 	if ( subKey )
   4734 	{
   4735 		RegCloseKey( subKey );
   4736 	}
   4737 
   4738 	if ( key )
   4739 	{
   4740 		RegCloseKey( key );
   4741 	}
   4742 }
   4743 
   4744 
   4745 mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
   4746 {
   4747 	char					domainUTF8[ 256 ];
   4748 	DomainAuthInfo			*foundInList;
   4749 	DomainAuthInfo			*ptr;
   4750 	char					outDomain[ 256 ];
   4751 	char					outKey[ 256 ];
   4752 	char					outSecret[ 256 ];
   4753 	OSStatus				err;
   4754 
   4755 	ConvertDomainNameToCString( inDomain, domainUTF8 );
   4756 
   4757 	// If we're able to find a secret for this domain
   4758 
   4759 	if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
   4760 	{
   4761 		domainname domain;
   4762 		domainname key;
   4763 
   4764 		// Tell the core about this secret
   4765 
   4766 		MakeDomainNameFromDNSNameString( &domain, outDomain );
   4767 		MakeDomainNameFromDNSNameString( &key, outKey );
   4768 
   4769 		for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
   4770 			if (SameDomainName(&foundInList->domain, &domain ) ) break;
   4771 
   4772 		ptr = foundInList;
   4773 
   4774 		if (!ptr)
   4775 		{
   4776 			ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
   4777 			require_action( ptr, exit, err = mStatus_NoMemoryErr );
   4778 		}
   4779 
   4780 		err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, NULL, 0, NULL );
   4781 		require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
   4782 
   4783 		debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
   4784 	}
   4785 
   4786 exit:
   4787 
   4788 	return;
   4789 }
   4790 
   4791 
   4792 mDNSlocal VOID CALLBACK
   4793 CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
   4794 {
   4795 	mDNS * const m = ( mDNS * const ) arg;
   4796 
   4797 	( void ) dwTimerLowValue;
   4798 	( void ) dwTimerHighValue;
   4799 
   4800 	CheckFileShares( m );
   4801 }
   4802 
   4803 
   4804 mDNSlocal unsigned __stdcall
   4805 SMBRegistrationThread( void * arg )
   4806 {
   4807 	mDNS * const m = ( mDNS * const ) arg;
   4808 	DNSServiceRef sref = NULL;
   4809 	HANDLE		handles[ 3 ];
   4810 	mDNSu8		txtBuf[ 256 ];
   4811 	mDNSu8	*	txtPtr;
   4812 	size_t		keyLen;
   4813 	size_t		valLen;
   4814 	mDNSIPPort	port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
   4815 	DNSServiceErrorType err;
   4816 
   4817 	DEBUG_UNUSED( arg );
   4818 
   4819 	handles[ 0 ] = gSMBThreadStopEvent;
   4820 	handles[ 1 ] = gSMBThreadRegisterEvent;
   4821 	handles[ 2 ] = gSMBThreadDeregisterEvent;
   4822 
   4823 	memset( txtBuf, 0, sizeof( txtBuf )  );
   4824 	txtPtr = txtBuf;
   4825 	keyLen = strlen( "netbios=" );
   4826 	valLen = strlen( m->p->nbname );
   4827 	require_action( valLen < 32, exit, err = kUnknownErr );	// This should never happen, but check to avoid further memory corruption
   4828 	*txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
   4829 	memcpy( txtPtr, "netbios=", keyLen );
   4830 	txtPtr += keyLen;
   4831 	if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
   4832 	keyLen = strlen( "domain=" );
   4833 	valLen = strlen( m->p->nbdomain );
   4834 	require_action( valLen < 32, exit, err = kUnknownErr );	// This should never happen, but check to avoid further memory corruption
   4835 	*txtPtr++ = ( mDNSu8 )( keyLen + valLen );
   4836 	memcpy( txtPtr, "domain=", keyLen );
   4837 	txtPtr += keyLen;
   4838 	if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
   4839 
   4840 	for ( ;; )
   4841 	{
   4842 		DWORD ret;
   4843 
   4844 		ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
   4845 
   4846 		if ( ret != WAIT_FAILED )
   4847 		{
   4848 			if ( ret == kSMBStopEvent )
   4849 			{
   4850 				break;
   4851 			}
   4852 			else if ( ret == kSMBRegisterEvent )
   4853 			{
   4854 				err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
   4855 
   4856 				if ( err )
   4857 				{
   4858 					LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
   4859 					sref = NULL;
   4860 					break;
   4861 				}
   4862 			}
   4863 			else if ( ret == kSMBDeregisterEvent )
   4864 			{
   4865 				if ( sref )
   4866 				{
   4867 					gDNSServiceRefDeallocate( sref );
   4868 					sref = NULL;
   4869 				}
   4870 			}
   4871 		}
   4872 		else
   4873 		{
   4874 			LogMsg( "SMBRegistrationThread:  WaitForMultipleObjects returned %d\n", GetLastError() );
   4875 			break;
   4876 		}
   4877 	}
   4878 
   4879 exit:
   4880 
   4881 	if ( sref != NULL )
   4882 	{
   4883 		gDNSServiceRefDeallocate( sref );
   4884 		sref = NULL;
   4885 	}
   4886 
   4887 	SetEvent( gSMBThreadQuitEvent );
   4888 	_endthreadex( 0 );
   4889 	return 0;
   4890 }
   4891 
   4892 
   4893 mDNSlocal void
   4894 CheckFileShares( mDNS * const m )
   4895 {
   4896 	PSHARE_INFO_1	bufPtr = ( PSHARE_INFO_1 ) NULL;
   4897 	DWORD			entriesRead = 0;
   4898 	DWORD			totalEntries = 0;
   4899 	DWORD			resume = 0;
   4900 	mDNSBool		advertise = mDNSfalse;
   4901 	mDNSBool		fileSharing = mDNSfalse;
   4902 	mDNSBool		printSharing = mDNSfalse;
   4903 	HKEY			key = NULL;
   4904 	BOOL			retry = FALSE;
   4905 	NET_API_STATUS  res;
   4906 	mStatus			err;
   4907 
   4908 	check( m );
   4909 
   4910 	// Only do this if we're not shutting down
   4911 
   4912 	require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
   4913 
   4914 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
   4915 
   4916 	if ( !err )
   4917 	{
   4918 		DWORD dwSize = sizeof( DWORD );
   4919 		RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
   4920 	}
   4921 
   4922 	if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
   4923 	{
   4924 		dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
   4925 
   4926 		res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
   4927 
   4928 		if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
   4929 		{
   4930 			PSHARE_INFO_1 p = bufPtr;
   4931 			DWORD i;
   4932 
   4933 			for( i = 0; i < entriesRead; i++ )
   4934 			{
   4935 				// We are only interested if the user is sharing anything other
   4936 				// than the built-in "print$" source
   4937 
   4938 				if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
   4939 				{
   4940 					fileSharing = mDNStrue;
   4941 				}
   4942 				else if ( p->shi1_type == STYPE_PRINTQ )
   4943 				{
   4944 					printSharing = mDNStrue;
   4945 				}
   4946 
   4947 				p++;
   4948 			}
   4949 
   4950 			NetApiBufferFree( bufPtr );
   4951 			bufPtr = NULL;
   4952 			retry = FALSE;
   4953 		}
   4954 		else if ( res == NERR_ServerNotStarted )
   4955 		{
   4956 			retry = TRUE;
   4957 		}
   4958 	}
   4959 
   4960 	if ( retry )
   4961 	{
   4962 		__int64			qwTimeout;
   4963 		LARGE_INTEGER   liTimeout;
   4964 
   4965 		qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
   4966 		liTimeout.LowPart  = ( DWORD )( qwTimeout & 0xFFFFFFFF );
   4967 		liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
   4968 
   4969 		SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
   4970 	}
   4971 
   4972 	if ( !m->p->smbFileSharing && fileSharing )
   4973 	{
   4974 		if ( !gSMBThread )
   4975 		{
   4976 			if ( !gDNSSDLibrary )
   4977 			{
   4978 				gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
   4979 				require_action( gDNSSDLibrary, exit, err = GetLastError() );
   4980 			}
   4981 
   4982 			if ( !gDNSServiceRegister )
   4983 			{
   4984 				gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
   4985 				require_action( gDNSServiceRegister, exit, err = GetLastError() );
   4986 			}
   4987 
   4988 			if ( !gDNSServiceRefDeallocate )
   4989 			{
   4990 				gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
   4991 				require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
   4992 			}
   4993 
   4994 			if ( !gSMBThreadRegisterEvent )
   4995 			{
   4996 				gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   4997 				require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
   4998 			}
   4999 
   5000 			if ( !gSMBThreadDeregisterEvent )
   5001 			{
   5002 				gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   5003 				require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
   5004 			}
   5005 
   5006 			if ( !gSMBThreadStopEvent )
   5007 			{
   5008 				gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   5009 				require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
   5010 			}
   5011 
   5012 			if ( !gSMBThreadQuitEvent )
   5013 			{
   5014 				gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   5015 				require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
   5016 			}
   5017 
   5018 			gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
   5019 			require_action( gSMBThread != NULL, exit, err = GetLastError() );
   5020 		}
   5021 
   5022 		SetEvent( gSMBThreadRegisterEvent );
   5023 
   5024 		m->p->smbFileSharing = mDNStrue;
   5025 	}
   5026 	else if ( m->p->smbFileSharing && !fileSharing )
   5027 	{
   5028 		dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
   5029 
   5030 		if ( gSMBThreadDeregisterEvent != NULL )
   5031 		{
   5032 			SetEvent( gSMBThreadDeregisterEvent );
   5033 		}
   5034 
   5035 		m->p->smbFileSharing = mDNSfalse;
   5036 	}
   5037 
   5038 exit:
   5039 
   5040 	if ( key )
   5041 	{
   5042 		RegCloseKey( key );
   5043 	}
   5044 }
   5045 
   5046 
   5047 BOOL
   5048 IsWOMPEnabled( mDNS * const m )
   5049 {
   5050 	BOOL enabled;
   5051 
   5052 	mDNSInterfaceData * ifd;
   5053 
   5054 	enabled = FALSE;
   5055 
   5056 	for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
   5057 	{
   5058 		if ( IsWOMPEnabledForAdapter( ifd->name ) )
   5059 		{
   5060 			enabled = TRUE;
   5061 			break;
   5062 		}
   5063 	}
   5064 
   5065 	return enabled;
   5066 }
   5067 
   5068 
   5069 mDNSlocal mDNSu8
   5070 IsWOMPEnabledForAdapter( const char * adapterName )
   5071 {
   5072 	char						fileName[80];
   5073 	NDIS_OID					oid;
   5074     DWORD						count;
   5075     HANDLE						handle	= INVALID_HANDLE_VALUE;
   5076 	NDIS_PNP_CAPABILITIES	*	pNPC	= NULL;
   5077 	int							err;
   5078 	mDNSu8						ok		= TRUE;
   5079 
   5080 	require_action( adapterName != NULL, exit, ok = FALSE );
   5081 
   5082 	dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
   5083 
   5084     // Construct a device name to pass to CreateFile
   5085 
   5086 	strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
   5087 	strcat_s( fileName, sizeof( fileName ), adapterName );
   5088     handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
   5089 	require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
   5090 
   5091 	// We successfully opened the driver, format the IOCTL to pass the driver.
   5092 
   5093 	oid = OID_PNP_CAPABILITIES;
   5094 	pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
   5095 	require_action( pNPC != NULL, exit, ok = FALSE );
   5096 	ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
   5097 	err = translate_errno( ok, GetLastError(), kUnknownErr );
   5098 	require_action( !err, exit, ok = FALSE );
   5099 	ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
   5100 
   5101 exit:
   5102 
   5103 	if ( pNPC != NULL )
   5104 	{
   5105 		free( pNPC );
   5106 	}
   5107 
   5108     if ( handle != INVALID_HANDLE_VALUE )
   5109     {
   5110 		CloseHandle( handle );
   5111     }
   5112 
   5113 	dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
   5114 
   5115 	return ( mDNSu8 ) ok;
   5116 }
   5117 
   5118 
   5119 void
   5120 DispatchSocketEvents( mDNS * const inMDNS )
   5121 {
   5122 	UDPSocket * udpSock;
   5123 	TCPSocket * tcpSock;
   5124 
   5125 	while ( ( udpSock = ( UDPSocket* ) gUDPDispatchableSockets.Head ) != NULL )
   5126 	{
   5127 		dlog( kDebugLevelChatty, DEBUG_NAME "%s: calling DispatchUDPEvent on socket %d, error = %d, bytesTransferred = %d\n",
   5128 		                                     __ROUTINE__, udpSock->fd, udpSock->overlapped.error, udpSock->overlapped.bytesTransferred );
   5129 		RemoveFromList( &gUDPDispatchableSockets, udpSock );
   5130 		DispatchUDPEvent( inMDNS, udpSock );
   5131 	}
   5132 
   5133 	while ( ( tcpSock = ( TCPSocket* ) gTCPDispatchableSockets.Head ) != NULL )
   5134 	{
   5135 		dlog( kDebugLevelChatty, DEBUG_NAME "%s: calling DispatchTCPEvent on socket %d, error = %d, bytesTransferred = %d\n",
   5136 		                                     __ROUTINE__, tcpSock->fd, tcpSock->overlapped.error, tcpSock->overlapped.bytesTransferred );
   5137 		RemoveFromList( &gTCPDispatchableSockets, tcpSock );
   5138 		DispatchTCPEvent( inMDNS, tcpSock );
   5139 	}
   5140 }
   5141 
   5142 
   5143 mDNSlocal void
   5144 DispatchUDPEvent( mDNS * const inMDNS, UDPSocket * sock )
   5145 {
   5146 	( void ) inMDNS;
   5147 
   5148 	// If we've closed the socket, then we want to ignore
   5149 	// this read.  The packet might have been queued before
   5150 	// the socket was closed.
   5151 
   5152 	if ( sock->fd != INVALID_SOCKET )
   5153 	{
   5154 		const mDNSInterfaceID	iid = sock->ifd ? sock->ifd->interfaceInfo.InterfaceID : NULL;
   5155 		mDNSu8				*	end = ( (mDNSu8 *) &sock->packet ) + sock->overlapped.bytesTransferred;
   5156 
   5157 		dlog( kDebugLevelChatty, DEBUG_NAME "calling mDNSCoreReceive on socket: %d\n", sock->fd );
   5158 		mDNSCoreReceive( sock->m, &sock->packet, end, &sock->overlapped.srcAddr, sock->overlapped.srcPort, &sock->overlapped.dstAddr, sock->overlapped.dstPort, iid );
   5159 	}
   5160 
   5161 	// If the socket is still good, then start up another asynchronous read
   5162 
   5163 	if ( sock->fd != INVALID_SOCKET )
   5164 	{
   5165 		int err = UDPBeginRecv( sock );
   5166 		check_noerr( err );
   5167 	}
   5168 }
   5169 
   5170 
   5171 mDNSlocal void
   5172 DispatchTCPEvent( mDNS * const inMDNS, TCPSocket * sock )
   5173 {
   5174 	( void ) inMDNS;
   5175 
   5176 	if ( sock->fd != INVALID_SOCKET )
   5177 	{
   5178 		sock->eptr += sock->overlapped.bytesTransferred;
   5179 		sock->lastError = sock->overlapped.error;
   5180 
   5181 		if ( !sock->overlapped.error && !sock->overlapped.bytesTransferred )
   5182 		{
   5183 			sock->closed = TRUE;
   5184 		}
   5185 
   5186 		if ( sock->readEventHandler != NULL )
   5187 		{
   5188 			dlog( kDebugLevelChatty, DEBUG_NAME "calling TCP read handler  on socket: %d\n", sock->fd );
   5189 			sock->readEventHandler( sock );
   5190 		}
   5191 	}
   5192 
   5193 	// If the socket is still good, then start up another asynchronous read
   5194 
   5195 	if ( !sock->closed && ( sock->fd != INVALID_SOCKET ) )
   5196 	{
   5197 		int err = TCPBeginRecv( sock );
   5198 		check_noerr( err );
   5199 	}
   5200 }
   5201