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
77static 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
91mDNSlocal mStatus			SetupNiceName( mDNS * const inMDNS );
92mDNSlocal mStatus			SetupHostName( mDNS * const inMDNS );
93mDNSlocal mStatus			SetupName( mDNS * const inMDNS );
94mDNSlocal mStatus			SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
95mDNSlocal mStatus			TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
96mDNSlocal void CALLBACK		FreeInterface( mDNSInterfaceData *inIFD );
97mDNSlocal mStatus			SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  );
98mDNSlocal mStatus			SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
99mDNSlocal OSStatus			GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
100mDNSlocal int				getifaddrs( struct ifaddrs **outAddrs );
101mDNSlocal void				freeifaddrs( struct ifaddrs *inAddrs );
102
103
104
105// Platform Accessors
106
107#ifdef	__cplusplus
108	extern "C" {
109#endif
110
111typedef struct mDNSPlatformInterfaceInfo	mDNSPlatformInterfaceInfo;
112struct	mDNSPlatformInterfaceInfo
113{
114	const char *		name;
115	mDNSAddr			ip;
116};
117
118
119mDNSexport mStatus	mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
120mDNSexport 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
128mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
129
130
131mDNSlocal DWORD				GetPrimaryInterface();
132mDNSlocal mStatus			AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
133mDNSlocal mDNSBool			CanReceiveUnicast( void );
134mDNSlocal mDNSBool			IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
135
136mDNSlocal mStatus			StringToAddress( mDNSAddr * ip, LPSTR string );
137mDNSlocal mStatus			RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
138mDNSlocal struct ifaddrs*	myGetIfAddrs(int refresh);
139mDNSlocal OSStatus			TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
140mDNSlocal OSStatus			WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
141mDNSlocal void				TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context );
142mDNSlocal void				TCPCanRead( TCPSocket * sock );
143mDNSlocal mStatus			TCPBeginRecv( TCPSocket * sock );
144mDNSlocal void CALLBACK		TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
145mDNSlocal void				TCPCloseSocket( TCPSocket * socket );
146mDNSlocal void CALLBACK		TCPFreeSocket( TCPSocket *sock );
147mDNSlocal OSStatus			UDPBeginRecv( UDPSocket * socket );
148mDNSlocal void CALLBACK		UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
149mDNSlocal void				UDPCloseSocket( UDPSocket * sock );
150mDNSlocal void CALLBACK		UDPFreeSocket( UDPSocket * sock );
151mDNSlocal mStatus           SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
152mDNSlocal void				GetDDNSFQDN( domainname *const fqdn );
153#ifdef UNICODE
154mDNSlocal void				GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
155#else
156mDNSlocal void				GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
157#endif
158mDNSlocal void				SetDomainSecrets( mDNS * const inMDNS );
159mDNSlocal void				SetDomainSecret( mDNS * const m, const domainname * inDomain );
160mDNSlocal VOID CALLBACK		CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
161mDNSlocal void				CheckFileShares( mDNS * const inMDNS );
162mDNSlocal void				SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
163mDNSlocal mDNSu8			IsWOMPEnabledForAdapter( const char * adapterName );
164mDNSlocal void				DispatchUDPEvent( mDNS * const m, UDPSocket * sock );
165mDNSlocal 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
179mDNSlocal mDNS_PlatformSupport	gMDNSPlatformSupport;
180mDNSs32							mDNSPlatformOneSecond	= 0;
181mDNSlocal UDPSocket		*		gUDPSockets				= NULL;
182mDNSlocal int					gUDPNumSockets			= 0;
183mDNSlocal GenLinkedList			gUDPDispatchableSockets;
184mDNSlocal 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
219typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
220typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
221typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
222
223static fnCryptAcquireContext g_lpCryptAcquireContext 	= NULL;
224static fnCryptReleaseContext g_lpCryptReleaseContext 	= NULL;
225static fnCryptGenRandom		 g_lpCryptGenRandom 		= NULL;
226static HINSTANCE			 g_hAAPI32 					= NULL;
227static HCRYPTPROV			 g_hProvider 				= ( ULONG_PTR ) NULL;
228
229
230typedef 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
247typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
248
249mDNSlocal HMODULE					gDNSSDLibrary				= NULL;
250mDNSlocal DNSServiceRegisterFunc	gDNSServiceRegister			= NULL;
251mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate	= NULL;
252mDNSlocal HANDLE					gSMBThread					= NULL;
253mDNSlocal HANDLE					gSMBThreadRegisterEvent		= NULL;
254mDNSlocal HANDLE					gSMBThreadDeregisterEvent	= NULL;
255mDNSlocal HANDLE					gSMBThreadStopEvent			= NULL;
256mDNSlocal 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
272mDNSexport 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
418exit:
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
433mDNSexport 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
555mDNSexport void	mDNSPlatformLock( const mDNS * const inMDNS )
556{
557	( void ) inMDNS;
558}
559
560//===========================================================================================================================
561//	mDNSPlatformUnlock
562//===========================================================================================================================
563
564mDNSexport void	mDNSPlatformUnlock( const mDNS * const inMDNS )
565{
566	( void ) inMDNS;
567}
568
569//===========================================================================================================================
570//	mDNSPlatformStrCopy
571//===========================================================================================================================
572
573mDNSexport 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
585mDNSexport 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
610exit:
611	return( (mDNSu32)( src - (const char *) inSrc ) - 1 );
612}
613
614//===========================================================================================================================
615//	mDNSPlatformStrLen
616//===========================================================================================================================
617
618mDNSexport mDNSu32	mDNSPlatformStrLen( const void *inSrc )
619{
620	check( inSrc );
621
622	return( (mDNSu32) strlen( (const char *) inSrc ) );
623}
624
625//===========================================================================================================================
626//	mDNSPlatformMemCopy
627//===========================================================================================================================
628
629mDNSexport 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
641mDNSexport 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
653mDNSexport void	mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
654{
655	check( inDst );
656
657	memset( inDst, 0, inSize );
658}
659
660//===========================================================================================================================
661//	mDNSPlatformMemAllocate
662//===========================================================================================================================
663
664mDNSexport 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
680mDNSexport void	mDNSPlatformMemFree( void *inMem )
681{
682	check( inMem );
683
684	free( inMem );
685}
686
687//===========================================================================================================================
688//	mDNSPlatformRandomNumber
689//===========================================================================================================================
690
691mDNSexport 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
756exit:
757
758	if ( err )
759	{
760		randomNumber = rand();
761	}
762
763	return randomNumber;
764}
765
766//===========================================================================================================================
767//	mDNSPlatformTimeInit
768//===========================================================================================================================
769
770mDNSexport 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
780mDNSexport mDNSs32	mDNSPlatformRawTime( void )
781{
782	return( (mDNSs32) GetTickCount() );
783}
784
785//===========================================================================================================================
786//	mDNSPlatformUTC
787//===========================================================================================================================
788
789mDNSexport mDNSs32	mDNSPlatformUTC( void )
790{
791	return ( mDNSs32 ) time( NULL );
792}
793
794//===========================================================================================================================
795//	mDNSPlatformInterfaceNameToID
796//===========================================================================================================================
797
798mDNSexport 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
826exit:
827	return( err );
828}
829
830//===========================================================================================================================
831//	mDNSPlatformInterfaceIDToInfo
832//===========================================================================================================================
833
834mDNSexport 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
860exit:
861	return( err );
862}
863
864//===========================================================================================================================
865//	mDNSPlatformInterfaceIDfromInterfaceIndex
866//===========================================================================================================================
867
868mDNSexport 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
904mDNSexport 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
957TCPSocket *
958mDNSPlatformTCPSocket
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
1018exit:
1019
1020	if ( err && sock )
1021	{
1022		TCPFreeSocket( sock );
1023		sock = mDNSNULL;
1024	}
1025
1026	return sock;
1027}
1028
1029//===========================================================================================================================
1030//	mDNSPlatformTCPConnect
1031//===========================================================================================================================
1032
1033mStatus
1034mDNSPlatformTCPConnect
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
1094exit:
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
1108mDNSexport
1109mDNSexport 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
1124exit:
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
1140mDNSexport 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
1162mDNSexport 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
1215mDNSexport 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
1230exit:
1231
1232	return nsent;
1233}
1234
1235//===========================================================================================================================
1236//	mDNSPlatformTCPGetFD
1237//===========================================================================================================================
1238
1239mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
1240{
1241	return ( int ) sock->fd;
1242}
1243
1244
1245//===========================================================================================================================
1246//	TCPAddConnection
1247//===========================================================================================================================
1248
1249mStatus 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
1263exit:
1264
1265	return err;
1266}
1267
1268
1269//===========================================================================================================================
1270//	TCPDidConnect
1271//===========================================================================================================================
1272
1273mDNSlocal 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
1307exit:
1308
1309	if ( err && callback )
1310	{
1311		callback( sock, sock->userContext, TRUE, err );
1312	}
1313}
1314
1315
1316
1317//===========================================================================================================================
1318//	TCPCanRead
1319//===========================================================================================================================
1320
1321mDNSlocal 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
1336mDNSlocal 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
1358exit:
1359
1360	return err;
1361}
1362
1363
1364//===========================================================================================================================
1365//	TCPEndRecv
1366//===========================================================================================================================
1367
1368mDNSlocal 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
1387exit:
1388
1389	return;
1390}
1391
1392
1393
1394//===========================================================================================================================
1395//	mDNSPlatformUDPSocket
1396//===========================================================================================================================
1397
1398mDNSexport 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
1460exit:
1461
1462	if ( err && sock )
1463	{
1464		UDPFreeSocket( sock );
1465		sock = NULL;
1466	}
1467
1468	return sock;
1469}
1470
1471//===========================================================================================================================
1472//	mDNSPlatformUDPClose
1473//===========================================================================================================================
1474
1475mDNSexport 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
1523mDNSexport 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
1600exit:
1601	return( err );
1602}
1603
1604
1605mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
1606	{
1607	DEBUG_UNUSED( m );
1608	DEBUG_UNUSED( InterfaceID );
1609	}
1610
1611//===========================================================================================================================
1612//	mDNSPlatformSendRawPacket
1613//===========================================================================================================================
1614
1615mDNSexport 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
1622mDNSexport 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
1629mDNSexport 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
1636mDNSexport 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
1644mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
1645	{
1646	dlog( kDebugLevelInfo, "%s\n", msg );
1647	}
1648
1649mDNSexport 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
1674mDNSexport 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
1684mDNSexport mStatus
1685mDNSPlatformTLSSetupCerts(void)
1686{
1687	return mStatus_UnsupportedErr;
1688}
1689
1690//===========================================================================================================================
1691//	mDNSPlatformTLSTearDownCerts
1692//===========================================================================================================================
1693
1694mDNSexport void
1695mDNSPlatformTLSTearDownCerts(void)
1696{
1697}
1698
1699//===========================================================================================================================
1700//	mDNSPlatformSetDNSConfig
1701//===========================================================================================================================
1702
1703mDNSlocal void SetDNSServers( mDNS *const m );
1704mDNSlocal void SetSearchDomainList( void );
1705
1706mDNSexport 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
1732mDNSexport void
1733mDNSPlatformDynDNSHostNameStatusChanged(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
1762exit:
1763
1764	if ( key )
1765	{
1766		RegCloseKey( key );
1767	}
1768
1769	return;
1770}
1771
1772
1773mDNSexport 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
1789void
1790SetDomainSecrets( 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
1828mDNSlocal void SetDomainFromDHCP( void );
1829mDNSlocal void SetReverseMapSearchDomainList( void );
1830
1831mDNSlocal void
1832SetSearchDomainList( 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
1858exit:
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
1879mDNSlocal void
1880SetReverseMapSearchDomainList( 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
1915mDNSlocal void
1916SetDNSServers( 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
1990exit:
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
2008mDNSlocal void
2009SetDomainFromDHCP( 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
2078exit:
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
2101mDNSexport mStatus
2102mDNSPlatformGetPrimaryInterface( 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
2159exit:
2160
2161	if ( pAdapterInfo )
2162	{
2163		free( pAdapterInfo );
2164	}
2165
2166	return err;
2167}
2168
2169mDNSexport 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
2178mDNSexport 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 )
2195mDNSexport 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 )
2214mDNSexport 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
2239mStatus	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
2352mDNSlocal 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
2406mDNSlocal 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
2426mStatus	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
2663exit:
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
2680mStatus	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
2728mDNSlocal 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
2852exit:
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
2866mDNSlocal 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
2903mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
2904{
2905	free( inIFD );
2906}
2907
2908//===========================================================================================================================
2909//	SetupSocket
2910//===========================================================================================================================
2911
2912mDNSlocal 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
3104exit:
3105	if( IsValidSocket( sock ) )
3106	{
3107		close_compat( sock );
3108	}
3109	return( err );
3110}
3111
3112//===========================================================================================================================
3113//	SetupSocket
3114//===========================================================================================================================
3115
3116mDNSlocal 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
3170mDNSlocal 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
3241exit:
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
3256mDNSlocal 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
3369exit:
3370
3371	return;
3372}
3373
3374
3375//===========================================================================================================================
3376//	InterfaceListDidChange
3377//===========================================================================================================================
3378void 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//===========================================================================================================================
3409void 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//===========================================================================================================================
3422void 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//===========================================================================================================================
3437void 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//===========================================================================================================================
3454void 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//===========================================================================================================================
3466void 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
3484mDNSlocal 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
3528exit:
3529	return( err );
3530}
3531
3532#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3533//===========================================================================================================================
3534//	getifaddrs_ipv6
3535//===========================================================================================================================
3536
3537mDNSlocal 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
3818exit:
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
3836mDNSlocal 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
3966exit:
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
3987mDNSlocal 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
4037mDNSlocal DWORD
4038GetPrimaryInterface()
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
4082exit:
4083
4084	if ( pIpForwardTable != NULL )
4085	{
4086		free( pIpForwardTable );
4087	}
4088
4089	return index;
4090}
4091
4092
4093//===========================================================================================================================
4094//	AddressToIndexAndMask
4095//===========================================================================================================================
4096
4097mDNSlocal mStatus
4098AddressToIndexAndMask( 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
4143exit:
4144
4145	if ( pIPAddrTable )
4146	{
4147		free( pIPAddrTable );
4148	}
4149
4150	return err;
4151}
4152
4153
4154//===========================================================================================================================
4155//	CanReceiveUnicast
4156//===========================================================================================================================
4157
4158mDNSlocal 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
4189mDNSlocal 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
4216exit:
4217
4218	if ( addrs )
4219	{
4220		freeifaddrs( addrs );
4221	}
4222
4223	return ret;
4224}
4225
4226
4227//===========================================================================================================================
4228//	GetWindowsVersionString
4229//===========================================================================================================================
4230
4231mDNSlocal 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
4317exit:
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
4332mDNSlocal mStatus
4333RegQueryString( 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
4371exit:
4372
4373	return err;
4374}
4375
4376
4377//===========================================================================================================================
4378//	StringToAddress
4379//===========================================================================================================================
4380
4381mDNSlocal 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
4411exit:
4412
4413	return err;
4414}
4415
4416
4417//===========================================================================================================================
4418//	myGetIfAddrs
4419//===========================================================================================================================
4420
4421mDNSlocal struct ifaddrs*
4422myGetIfAddrs(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
4445mDNSlocal OSStatus
4446TCHARtoUTF8( 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
4456exit:
4457	return( err );
4458#else
4459	return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
4460#endif
4461}
4462
4463
4464//===========================================================================================================================
4465//	WindowsLatin1toUTF8
4466//===========================================================================================================================
4467
4468mDNSlocal OSStatus
4469WindowsLatin1toUTF8( 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
4496exit:
4497	if( utf16 ) free( utf16 );
4498	return( err );
4499}
4500
4501
4502//===========================================================================================================================
4503//	TCPCloseSocket
4504//===========================================================================================================================
4505
4506mDNSlocal void
4507TCPCloseSocket( 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
4525mDNSlocal void CALLBACK
4526TCPFreeSocket( 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
4552mDNSlocal void
4553UDPCloseSocket( 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
4571mDNSlocal void CALLBACK
4572UDPFreeSocket( 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
4591mDNSlocal 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
4617mDNSlocal 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
4645exit:
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
4662mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
4663#else
4664mDNSlocal 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
4731exit:
4732
4733	if ( subKey )
4734	{
4735		RegCloseKey( subKey );
4736	}
4737
4738	if ( key )
4739	{
4740		RegCloseKey( key );
4741	}
4742}
4743
4744
4745mDNSlocal 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
4786exit:
4787
4788	return;
4789}
4790
4791
4792mDNSlocal VOID CALLBACK
4793CheckFileSharesProc( 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
4804mDNSlocal unsigned __stdcall
4805SMBRegistrationThread( 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
4879exit:
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
4893mDNSlocal void
4894CheckFileShares( 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
5038exit:
5039
5040	if ( key )
5041	{
5042		RegCloseKey( key );
5043	}
5044}
5045
5046
5047BOOL
5048IsWOMPEnabled( 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
5069mDNSlocal mDNSu8
5070IsWOMPEnabledForAdapter( 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
5101exit:
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
5119void
5120DispatchSocketEvents( 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
5143mDNSlocal void
5144DispatchUDPEvent( 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
5171mDNSlocal void
5172DispatchTCPEvent( 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