Home | History | Annotate | Download | only in mdnsNSP
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2003-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 
     18 
     19 #include	<stdio.h>
     20 #include	<stdlib.h>
     21 #include	<string.h>
     22 
     23 #include	"ClientCommon.h"
     24 #include	"CommonServices.h"
     25 #include	"DebugServices.h"
     26 
     27 #include	<iphlpapi.h>
     28 #include	<guiddef.h>
     29 #include	<ws2spi.h>
     30 #include	<shlwapi.h>
     31 
     32 
     33 
     34 #include	"dns_sd.h"
     35 
     36 #pragma comment(lib, "DelayImp.lib")
     37 
     38 #ifdef _MSC_VER
     39 #define swprintf _snwprintf
     40 #define snprintf _snprintf
     41 #endif
     42 
     43 #define MAX_LABELS 128
     44 
     45 #if 0
     46 #pragma mark == Structures ==
     47 #endif
     48 
     49 //===========================================================================================================================
     50 //	Structures
     51 //===========================================================================================================================
     52 
     53 typedef struct	Query *		QueryRef;
     54 typedef struct	Query		Query;
     55 struct	Query
     56 {
     57 	QueryRef			next;
     58 	int					refCount;
     59 	DWORD				querySetFlags;
     60 	WSAQUERYSETW *		querySet;
     61 	size_t				querySetSize;
     62 	HANDLE				data4Event;
     63 	HANDLE				data6Event;
     64 	HANDLE				cancelEvent;
     65 	HANDLE				waitHandles[ 3 ];
     66 	DWORD				waitCount;
     67 	DNSServiceRef		resolver4;
     68 	DNSServiceRef		resolver6;
     69 	char				name[ kDNSServiceMaxDomainName ];
     70 	size_t				nameSize;
     71 	uint8_t				numValidAddrs;
     72 	uint32_t			addr4;
     73 	bool				addr4Valid;
     74 	uint8_t				addr6[16];
     75 	u_long				addr6ScopeId;
     76 	bool				addr6Valid;
     77 };
     78 
     79 #define BUFFER_INITIAL_SIZE		4192
     80 #define ALIASES_INITIAL_SIZE	5
     81 
     82 typedef struct HostsFile
     83 {
     84 	int			m_bufferSize;
     85 	char	*	m_buffer;
     86 	FILE	*	m_fp;
     87 } HostsFile;
     88 
     89 
     90 typedef struct HostsFileInfo
     91 {
     92 	struct hostent		m_host;
     93 	struct HostsFileInfo	*	m_next;
     94 } HostsFileInfo;
     95 
     96 
     97 #if 0
     98 #pragma mark == Prototypes ==
     99 #endif
    100 
    101 //===========================================================================================================================
    102 //	Prototypes
    103 //===========================================================================================================================
    104 
    105 // DLL Exports
    106 
    107 BOOL WINAPI		DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
    108 STDAPI			DllRegisterServer( void );
    109 STDAPI			DllRegisterServer( void );
    110 
    111 
    112 // NSP SPIs
    113 
    114 int	WSPAPI	NSPCleanup( LPGUID inProviderID );
    115 
    116 DEBUG_LOCAL int WSPAPI
    117 	NSPLookupServiceBegin(
    118 		LPGUID					inProviderID,
    119 		LPWSAQUERYSETW			inQuerySet,
    120 		LPWSASERVICECLASSINFOW	inServiceClassInfo,
    121 		DWORD					inFlags,
    122 		LPHANDLE				outLookup );
    123 
    124 DEBUG_LOCAL int WSPAPI
    125 	NSPLookupServiceNext(
    126 		HANDLE			inLookup,
    127 		DWORD			inFlags,
    128 		LPDWORD			ioBufferLength,
    129 		LPWSAQUERYSETW	outResults );
    130 
    131 DEBUG_LOCAL int WSPAPI	NSPLookupServiceEnd( HANDLE inLookup );
    132 
    133 DEBUG_LOCAL int WSPAPI
    134 	NSPSetService(
    135 		LPGUID					inProviderID,
    136 		LPWSASERVICECLASSINFOW	inServiceClassInfo,
    137 		LPWSAQUERYSETW			inRegInfo,
    138 		WSAESETSERVICEOP		inOperation,
    139 		DWORD					inFlags );
    140 
    141 DEBUG_LOCAL int WSPAPI	NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo );
    142 DEBUG_LOCAL int WSPAPI	NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID );
    143 DEBUG_LOCAL int WSPAPI	NSPGetServiceClassInfo(	LPGUID inProviderID, LPDWORD ioBufSize, LPWSASERVICECLASSINFOW ioServiceClassInfo );
    144 
    145 // Private
    146 
    147 #define	NSPLock()		EnterCriticalSection( &gLock );
    148 #define	NSPUnlock()		LeaveCriticalSection( &gLock );
    149 
    150 DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef );
    151 DEBUG_LOCAL OSStatus	QueryRetain( QueryRef inRef );
    152 DEBUG_LOCAL OSStatus	QueryRelease( QueryRef inRef );
    153 
    154 DEBUG_LOCAL void CALLBACK_COMPAT
    155 	QueryRecordCallback4(
    156 		DNSServiceRef		inRef,
    157 		DNSServiceFlags		inFlags,
    158 		uint32_t			inInterfaceIndex,
    159 		DNSServiceErrorType	inErrorCode,
    160 		const char *		inName,
    161 		uint16_t			inRRType,
    162 		uint16_t			inRRClass,
    163 		uint16_t			inRDataSize,
    164 		const void *		inRData,
    165 		uint32_t			inTTL,
    166 		void *				inContext );
    167 
    168 DEBUG_LOCAL void CALLBACK_COMPAT
    169 	QueryRecordCallback6(
    170 		DNSServiceRef		inRef,
    171 		DNSServiceFlags		inFlags,
    172 		uint32_t			inInterfaceIndex,
    173 		DNSServiceErrorType	inErrorCode,
    174 		const char *		inName,
    175 		uint16_t			inRRType,
    176 		uint16_t			inRRClass,
    177 		uint16_t			inRDataSize,
    178 		const void *		inRData,
    179 		uint32_t			inTTL,
    180 		void *				inContext );
    181 
    182 DEBUG_LOCAL OSStatus
    183 	QueryCopyQuerySet(
    184 		QueryRef 				inRef,
    185 		const WSAQUERYSETW *	inQuerySet,
    186 		DWORD 					inQuerySetFlags,
    187 		WSAQUERYSETW **			outQuerySet,
    188 		size_t *				outSize );
    189 
    190 DEBUG_LOCAL void
    191 	QueryCopyQuerySetTo(
    192 		QueryRef 				inRef,
    193 		const WSAQUERYSETW *	inQuerySet,
    194 		DWORD 					inQuerySetFlags,
    195 		WSAQUERYSETW *			outQuerySet );
    196 
    197 DEBUG_LOCAL size_t	QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags );
    198 
    199 #if( DEBUG )
    200 	void	DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet );
    201 
    202 	#define	dlog_query_set( LEVEL, SET )		DebugDumpQuerySet( LEVEL, SET )
    203 #else
    204 	#define	dlog_query_set( LEVEL, SET )
    205 #endif
    206 
    207 DEBUG_LOCAL BOOL		InHostsTable( const char * name );
    208 DEBUG_LOCAL BOOL		IsLocalName( HostsFileInfo * node );
    209 DEBUG_LOCAL BOOL		IsSameName( HostsFileInfo * node, const char * name );
    210 DEBUG_LOCAL OSStatus	HostsFileOpen( HostsFile ** self, const char * fname );
    211 DEBUG_LOCAL OSStatus	HostsFileClose( HostsFile * self );
    212 DEBUG_LOCAL void		HostsFileInfoFree( HostsFileInfo * info );
    213 DEBUG_LOCAL OSStatus	HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo );
    214 DEBUG_LOCAL DWORD		GetScopeId( DWORD ifIndex );
    215 
    216 #ifdef ENABLE_REVERSE_LOOKUP
    217 DEBUG_LOCAL OSStatus	IsReverseLookup( LPCWSTR name, size_t size );
    218 #endif
    219 
    220 
    221 #if 0
    222 #pragma mark == Globals ==
    223 #endif
    224 
    225 //===========================================================================================================================
    226 //	Globals
    227 //===========================================================================================================================
    228 
    229 // {B600E6E9-553B-4a19-8696-335E5C896153}
    230 DEBUG_LOCAL HINSTANCE				gInstance			= NULL;
    231 DEBUG_LOCAL wchar_t				*	gNSPName			= L"mdnsNSP";
    232 DEBUG_LOCAL GUID					gNSPGUID			= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
    233 DEBUG_LOCAL LONG					gRefCount			= 0;
    234 DEBUG_LOCAL CRITICAL_SECTION		gLock;
    235 DEBUG_LOCAL bool					gLockInitialized 	= false;
    236 DEBUG_LOCAL QueryRef				gQueryList	 		= NULL;
    237 DEBUG_LOCAL HostsFileInfo		*	gHostsFileInfo		= NULL;
    238 typedef DWORD
    239 	( WINAPI * GetAdaptersAddressesFunctionPtr )(
    240 			ULONG 					inFamily,
    241 			DWORD 					inFlags,
    242 			PVOID 					inReserved,
    243 			PIP_ADAPTER_ADDRESSES 	inAdapter,
    244 			PULONG					outBufferSize );
    245 
    246 DEBUG_LOCAL HMODULE								gIPHelperLibraryInstance			= NULL;
    247 DEBUG_LOCAL GetAdaptersAddressesFunctionPtr		gGetAdaptersAddressesFunctionPtr	= NULL;
    248 
    249 
    250 
    251 #if 0
    252 #pragma mark -
    253 #endif
    254 
    255 //===========================================================================================================================
    256 //	DllMain
    257 //===========================================================================================================================
    258 
    259 BOOL APIENTRY	DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
    260 {
    261 	DEBUG_USE_ONLY( inInstance );
    262 	DEBUG_UNUSED( inReserved );
    263 
    264 	switch( inReason )
    265 	{
    266 		case DLL_PROCESS_ATTACH:
    267 			gInstance = inInstance;
    268 			gHostsFileInfo	= NULL;
    269 			debug_initialize( kDebugOutputTypeWindowsEventLog, "mDNS NSP", inInstance );
    270 			debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelNotice );
    271 			dlog( kDebugLevelTrace, "\n" );
    272 			dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
    273 
    274 			break;
    275 
    276 		case DLL_PROCESS_DETACH:
    277 			HostsFileInfoFree( gHostsFileInfo );
    278 			gHostsFileInfo = NULL;
    279 			dlog( kDebugLevelVerbose, "%s: process detach\n", __ROUTINE__ );
    280 			break;
    281 
    282 		case DLL_THREAD_ATTACH:
    283 			dlog( kDebugLevelVerbose, "%s: thread attach\n", __ROUTINE__ );
    284 			break;
    285 
    286 		case DLL_THREAD_DETACH:
    287 			dlog( kDebugLevelVerbose, "%s: thread detach\n", __ROUTINE__ );
    288 			break;
    289 
    290 		default:
    291 			dlog( kDebugLevelNotice, "%s: unknown reason code (%d)\n", __ROUTINE__, inReason );
    292 			break;
    293 	}
    294 
    295 	return( TRUE );
    296 }
    297 
    298 
    299 //===========================================================================================================================
    300 //	DllRegisterServer
    301 //===========================================================================================================================
    302 
    303 STDAPI	DllRegisterServer( void )
    304 {
    305 	WSADATA		wsd;
    306 	WCHAR		path[ MAX_PATH ];
    307 	HRESULT		err;
    308 
    309 	dlog( kDebugLevelTrace, "DllRegisterServer\n" );
    310 
    311 	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
    312 	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
    313 	require_noerr( err, exit );
    314 
    315 	// Unregister before registering to workaround an installer
    316 	// problem during upgrade installs.
    317 
    318 	WSCUnInstallNameSpace( &gNSPGUID );
    319 
    320 	err = GetModuleFileNameW( gInstance, path, MAX_PATH );
    321 	err = translate_errno( err != 0, errno_compat(), kUnknownErr );
    322 	require_noerr( err, exit );
    323 
    324 	err = WSCInstallNameSpace( gNSPName, path, NS_DNS, 1, &gNSPGUID );
    325 	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
    326 	require_noerr( err, exit );
    327 
    328 exit:
    329 
    330 	WSACleanup();
    331 	return( err );
    332 }
    333 
    334 //===========================================================================================================================
    335 //	DllUnregisterServer
    336 //===========================================================================================================================
    337 
    338 STDAPI	DllUnregisterServer( void )
    339 {
    340 	WSADATA		wsd;
    341 	HRESULT err;
    342 
    343 	dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
    344 
    345 	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
    346 	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
    347 	require_noerr( err, exit );
    348 
    349 	err = WSCUnInstallNameSpace( &gNSPGUID );
    350 	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
    351 	require_noerr( err, exit );
    352 
    353 exit:
    354 
    355 	WSACleanup();
    356 	return err;
    357 }
    358 
    359 
    360 //===========================================================================================================================
    361 //	NSPStartup
    362 //
    363 //	This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
    364 //===========================================================================================================================
    365 
    366 int WSPAPI	NSPStartup( LPGUID inProviderID, LPNSP_ROUTINE outRoutines )
    367 {
    368 	OSStatus		err;
    369 
    370 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    371 	dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
    372 
    373 	// Only initialize if this is the first time NSPStartup is called.
    374 
    375 	if( InterlockedIncrement( &gRefCount ) != 1 )
    376 	{
    377 		err = NO_ERROR;
    378 		goto exit;
    379 	}
    380 
    381 	// Initialize our internal state.
    382 
    383 	InitializeCriticalSection( &gLock );
    384 	gLockInitialized = true;
    385 
    386 	// Set the size to exclude NSPIoctl because we don't implement it.
    387 
    388 	outRoutines->cbSize					= FIELD_OFFSET( NSP_ROUTINE, NSPIoctl );
    389 	outRoutines->dwMajorVersion			= 4;
    390 	outRoutines->dwMinorVersion			= 4;
    391 	outRoutines->NSPCleanup				= NSPCleanup;
    392 	outRoutines->NSPLookupServiceBegin	= NSPLookupServiceBegin;
    393 	outRoutines->NSPLookupServiceNext	= NSPLookupServiceNext;
    394 	outRoutines->NSPLookupServiceEnd	= NSPLookupServiceEnd;
    395 	outRoutines->NSPSetService			= NSPSetService;
    396 	outRoutines->NSPInstallServiceClass	= NSPInstallServiceClass;
    397 	outRoutines->NSPRemoveServiceClass	= NSPRemoveServiceClass;
    398 	outRoutines->NSPGetServiceClassInfo	= NSPGetServiceClassInfo;
    399 
    400 	// See if we can get the address for the GetAdaptersAddresses() API.  This is only in XP, but we want our
    401 	// code to run on older versions of Windows
    402 
    403 	if ( !gIPHelperLibraryInstance )
    404 	{
    405 		gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
    406 		if( gIPHelperLibraryInstance )
    407 		{
    408 			gGetAdaptersAddressesFunctionPtr = (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
    409 		}
    410 	}
    411 
    412 	err = NO_ERROR;
    413 
    414 exit:
    415 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    416 	if( err != NO_ERROR )
    417 	{
    418 		NSPCleanup( inProviderID );
    419 		SetLastError( (DWORD) err );
    420 		return( SOCKET_ERROR );
    421 	}
    422 	return( NO_ERROR );
    423 }
    424 
    425 //===========================================================================================================================
    426 //	NSPCleanup
    427 //
    428 //	This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
    429 //===========================================================================================================================
    430 
    431 int	WSPAPI	NSPCleanup( LPGUID inProviderID )
    432 {
    433 	DEBUG_USE_ONLY( inProviderID );
    434 
    435 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    436 	dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
    437 
    438 	// Only initialize if this is the first time NSPStartup is called.
    439 
    440 	if( InterlockedDecrement( &gRefCount ) != 0 )
    441 	{
    442 		goto exit;
    443 	}
    444 
    445 	// Stop any outstanding queries.
    446 
    447 	if( gLockInitialized )
    448 	{
    449 		NSPLock();
    450 	}
    451 	while( gQueryList )
    452 	{
    453 		check_string( gQueryList->refCount == 1, "NSPCleanup with outstanding queries!" );
    454 		QueryRelease( gQueryList );
    455 	}
    456 	if( gLockInitialized )
    457 	{
    458 		NSPUnlock();
    459 	}
    460 
    461 	if( gLockInitialized )
    462 	{
    463 		gLockInitialized = false;
    464 		DeleteCriticalSection( &gLock );
    465 	}
    466 
    467 	if( gIPHelperLibraryInstance )
    468 	{
    469 		BOOL ok;
    470 
    471 		ok = FreeLibrary( gIPHelperLibraryInstance );
    472 		check_translated_errno( ok, GetLastError(), kUnknownErr );
    473 		gIPHelperLibraryInstance = NULL;
    474 	}
    475 
    476 exit:
    477 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    478 	return( NO_ERROR );
    479 }
    480 
    481 //===========================================================================================================================
    482 //	NSPLookupServiceBegin
    483 //
    484 //	This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
    485 //	that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
    486 //	opposed to specifying the query parameters each time.
    487 //===========================================================================================================================
    488 
    489 DEBUG_LOCAL int WSPAPI
    490 	NSPLookupServiceBegin(
    491 		LPGUID					inProviderID,
    492 		LPWSAQUERYSETW			inQuerySet,
    493 		LPWSASERVICECLASSINFOW	inServiceClassInfo,
    494 		DWORD					inFlags,
    495 		LPHANDLE				outLookup )
    496 {
    497 	OSStatus		err;
    498 	QueryRef		obj;
    499 	LPCWSTR			name;
    500 	size_t			size;
    501 	LPCWSTR			p;
    502 	DWORD           type;
    503 	DWORD			n;
    504 	DWORD			i;
    505 	INT				family;
    506 	INT				protocol;
    507 
    508 	DEBUG_UNUSED( inProviderID );
    509 	DEBUG_UNUSED( inServiceClassInfo );
    510 
    511 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    512 
    513 	obj = NULL;
    514 	require_action( inQuerySet, exit, err = WSAEINVAL );
    515 	name = inQuerySet->lpszServiceInstanceName;
    516 	require_action_quiet( name, exit, err = WSAEINVAL );
    517 	require_action( outLookup, exit, err = WSAEINVAL );
    518 
    519 	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__, inFlags, name );
    520 	dlog_query_set( kDebugLevelVerbose, inQuerySet );
    521 
    522 	// Check if we can handle this type of request and if we support any of the protocols being requested.
    523 	// We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
    524 
    525 	require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
    526 
    527 	type = inQuerySet->dwNameSpace;
    528 	require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
    529 
    530 	n = inQuerySet->dwNumberOfProtocols;
    531 	if( n > 0 )
    532 	{
    533 		require_action( inQuerySet->lpafpProtocols, exit, err = WSAEINVAL );
    534 		for( i = 0; i < n; ++i )
    535 		{
    536 			family = inQuerySet->lpafpProtocols[ i ].iAddressFamily;
    537 			protocol = inQuerySet->lpafpProtocols[ i ].iProtocol;
    538 			if( ( family == AF_INET ) && ( ( protocol == IPPROTO_UDP ) || ( protocol == IPPROTO_TCP ) ) )
    539 			{
    540 				break;
    541 			}
    542 		}
    543 		require_action_quiet( i < n, exit, err = WSASERVICE_NOT_FOUND );
    544 	}
    545 
    546 	// Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
    547 	// The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
    548 	// insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
    549 	// manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
    550 	// libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
    551 
    552 	for( p = name; *p; ++p ) {}		// Find end of string
    553 	size = (size_t)( p - name );
    554 	require_action_quiet( size > sizeof_string( ".local" ), exit, err = WSASERVICE_NOT_FOUND );
    555 
    556 	p = name + ( size - 1 );
    557 	p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
    558 	if	( ( ( p[ 0 ] != '.' )						||
    559 		( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) )	||
    560 		( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) )	||
    561 		( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) )	||
    562 		( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) )	||
    563 		( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
    564 	{
    565 #ifdef ENABLE_REVERSE_LOOKUP
    566 
    567 		err = IsReverseLookup( name, size );
    568 
    569 #else
    570 
    571 		err = WSASERVICE_NOT_FOUND;
    572 
    573 #endif
    574 
    575 		require_noerr( err, exit );
    576 	}
    577 	else
    578 	{
    579 		const char	*	replyDomain;
    580 		char			translated[ kDNSServiceMaxDomainName ];
    581 		int				n;
    582 		int				labels		= 0;
    583 		const char	*	label[MAX_LABELS];
    584 		char			text[64];
    585 
    586 		n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL );
    587 		require_action( n > 0, exit, err = WSASERVICE_NOT_FOUND );
    588 
    589 		// <rdar://problem/4050633>
    590 
    591 		// Don't resolve multi-label name
    592 
    593 		// <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
    594 		// Add checks for GetNextLabel returning NULL, individual labels being greater than
    595 		// 64 bytes, and the number of labels being greater than MAX_LABELS
    596 		replyDomain = translated;
    597 
    598 		while (replyDomain && *replyDomain && labels < MAX_LABELS)
    599 		{
    600 			label[labels++]	= replyDomain;
    601 			replyDomain		= GetNextLabel(replyDomain, text);
    602 		}
    603 
    604 		require_action( labels == 2, exit, err = WSASERVICE_NOT_FOUND );
    605 
    606 		// <rdar://problem/3936771>
    607 		//
    608 		// Check to see if the name of this host is in the hosts table. If so,
    609 		// don't try and resolve it
    610 
    611 		require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
    612 	}
    613 
    614 	// The name ends in .local ( and isn't in the hosts table ), .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
    615 
    616 	NSPLock();
    617 
    618 	err = QueryCreate( inQuerySet, inFlags, &obj );
    619 	NSPUnlock();
    620 	require_noerr( err, exit );
    621 
    622 	*outLookup = (HANDLE) obj;
    623 
    624 exit:
    625 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    626 	if( err != NO_ERROR )
    627 	{
    628 		SetLastError( (DWORD) err );
    629 		return( SOCKET_ERROR );
    630 	}
    631 	return( NO_ERROR );
    632 }
    633 
    634 //===========================================================================================================================
    635 //	NSPLookupServiceNext
    636 //
    637 //	This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
    638 //	query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
    639 //	in the lpqsResults parameter.
    640 //===========================================================================================================================
    641 
    642 DEBUG_LOCAL int WSPAPI
    643 	NSPLookupServiceNext(
    644 		HANDLE			inLookup,
    645 		DWORD			inFlags,
    646 		LPDWORD			ioSize,
    647 		LPWSAQUERYSETW	outResults )
    648 {
    649 	BOOL			data4;
    650 	BOOL			data6;
    651 	OSStatus		err;
    652 	QueryRef		obj;
    653 	DWORD			waitResult;
    654 	size_t			size;
    655 
    656 	DEBUG_USE_ONLY( inFlags );
    657 
    658 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    659 
    660 	data4 = FALSE;
    661 	data6 = FALSE;
    662 	obj = NULL;
    663 	NSPLock();
    664 	err = QueryRetain( (QueryRef) inLookup );
    665 	require_noerr( err, exit );
    666 	obj = (QueryRef) inLookup;
    667 	require_action( ioSize, exit, err = WSAEINVAL );
    668 	require_action( outResults, exit, err = WSAEINVAL );
    669 
    670 	dlog( kDebugLevelTrace, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__, inLookup, inFlags, *ioSize );
    671 
    672 	// Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
    673 
    674 	NSPUnlock();
    675 	waitResult = WaitForMultipleObjects( obj->waitCount, obj->waitHandles, FALSE, 2 * 1000 );
    676 	NSPLock();
    677 	require_action_quiet( waitResult != ( WAIT_OBJECT_0 ), exit, err = WSA_E_CANCELLED );
    678 	err = translate_errno( ( waitResult == WAIT_OBJECT_0 + 1 ) || ( waitResult == WAIT_OBJECT_0 + 2 ), (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
    679 	require_noerr_quiet( err, exit );
    680 
    681 	// If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
    682 
    683 	if ( waitResult == WAIT_OBJECT_0 + 1 )
    684 	{
    685 		data4 = TRUE;
    686 		data6 = WaitForSingleObject( obj->data6Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
    687 	}
    688 
    689 	// Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
    690 
    691 	else if ( waitResult == WAIT_OBJECT_0 + 2 )
    692 	{
    693 		data4 = WaitForSingleObject( obj->data4Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
    694 		data6 = TRUE;
    695 	}
    696 
    697 	if ( data4 )
    698 	{
    699 		__try
    700 		{
    701 			err = DNSServiceProcessResult(obj->resolver4);
    702 		}
    703 		__except( EXCEPTION_EXECUTE_HANDLER )
    704 		{
    705 			err = kUnknownErr;
    706 		}
    707 
    708 		require_noerr( err, exit );
    709 	}
    710 
    711 	if ( data6 )
    712 	{
    713 		__try
    714 		{
    715 			err = DNSServiceProcessResult( obj->resolver6 );
    716 		}
    717 		__except( EXCEPTION_EXECUTE_HANDLER )
    718 		{
    719 			err = kUnknownErr;
    720 		}
    721 
    722 		require_noerr( err, exit );
    723 	}
    724 
    725 	require_action_quiet( obj->addr4Valid || obj->addr6Valid, exit, err = WSA_E_NO_MORE );
    726 
    727 	// Copy the externalized query results to the callers buffer (if it fits).
    728 
    729 	size = QueryCopyQuerySetSize( obj, obj->querySet, obj->querySetFlags );
    730 	require_action( size <= (size_t) *ioSize, exit, err = WSAEFAULT );
    731 
    732 	QueryCopyQuerySetTo( obj, obj->querySet, obj->querySetFlags, outResults );
    733 	outResults->dwOutputFlags = RESULT_IS_ADDED;
    734 	obj->addr4Valid = false;
    735 	obj->addr6Valid = false;
    736 
    737 exit:
    738 	if( obj )
    739 	{
    740 		QueryRelease( obj );
    741 	}
    742 	NSPUnlock();
    743 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    744 	if( err != NO_ERROR )
    745 	{
    746 		SetLastError( (DWORD) err );
    747 		return( SOCKET_ERROR );
    748 	}
    749 	return( NO_ERROR );
    750 }
    751 
    752 //===========================================================================================================================
    753 //	NSPLookupServiceEnd
    754 //
    755 //	This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
    756 //	indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
    757 //	allocated resources associated with the query.
    758 //===========================================================================================================================
    759 
    760 DEBUG_LOCAL int WSPAPI	NSPLookupServiceEnd( HANDLE inLookup )
    761 {
    762 	OSStatus		err;
    763 
    764 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    765 
    766 	dlog( kDebugLevelTrace, "%s (lookup=%#p)\n", __ROUTINE__, inLookup );
    767 
    768 	NSPLock();
    769 	err = QueryRelease( (QueryRef) inLookup );
    770 	NSPUnlock();
    771 	require_noerr( err, exit );
    772 
    773 exit:
    774 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    775 	if( err != NO_ERROR )
    776 	{
    777 		SetLastError( (DWORD) err );
    778 		return( SOCKET_ERROR );
    779 	}
    780 	return( NO_ERROR );
    781 }
    782 
    783 //===========================================================================================================================
    784 //	NSPSetService
    785 //
    786 //	This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
    787 //	deregister an instance of a server with our service. For registration, the user needs to associate the server with a
    788 //	service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
    789 //	contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
    790 //===========================================================================================================================
    791 
    792 DEBUG_LOCAL int WSPAPI
    793 	NSPSetService(
    794 		LPGUID					inProviderID,
    795 		LPWSASERVICECLASSINFOW	inServiceClassInfo,
    796 		LPWSAQUERYSETW			inRegInfo,
    797 		WSAESETSERVICEOP		inOperation,
    798 		DWORD					inFlags )
    799 {
    800 	DEBUG_UNUSED( inProviderID );
    801 	DEBUG_UNUSED( inServiceClassInfo );
    802 	DEBUG_UNUSED( inRegInfo );
    803 	DEBUG_UNUSED( inOperation );
    804 	DEBUG_UNUSED( inFlags );
    805 
    806 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    807 	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
    808 
    809 	// We don't allow services to be registered so always return an error.
    810 
    811 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    812 	return( WSAEINVAL );
    813 }
    814 
    815 //===========================================================================================================================
    816 //	NSPInstallServiceClass
    817 //
    818 //	This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
    819 //	is used to define certain characteristics for a group of services. After a service class is registered, an actual
    820 //	instance of a server may be registered.
    821 //===========================================================================================================================
    822 
    823 DEBUG_LOCAL int WSPAPI	NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo )
    824 {
    825 	DEBUG_UNUSED( inProviderID );
    826 	DEBUG_UNUSED( inServiceClassInfo );
    827 
    828 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    829 	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
    830 
    831 	// We don't allow service classes to be installed so always return an error.
    832 
    833 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    834 	return( WSA_INVALID_PARAMETER );
    835 }
    836 
    837 //===========================================================================================================================
    838 //	NSPRemoveServiceClass
    839 //
    840 //	This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
    841 //	class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
    842 //	service class.
    843 //===========================================================================================================================
    844 
    845 DEBUG_LOCAL int WSPAPI	NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID )
    846 {
    847 	DEBUG_UNUSED( inProviderID );
    848 	DEBUG_UNUSED( inServiceClassID );
    849 
    850 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    851 	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
    852 
    853 	// We don't allow service classes to be installed so always return an error.
    854 
    855 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    856 	return( WSATYPE_NOT_FOUND );
    857 }
    858 
    859 //===========================================================================================================================
    860 //	NSPGetServiceClassInfo
    861 //
    862 //	This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
    863 //	a given service class.
    864 //===========================================================================================================================
    865 
    866 DEBUG_LOCAL int WSPAPI	NSPGetServiceClassInfo(	LPGUID inProviderID, LPDWORD ioSize, LPWSASERVICECLASSINFOW ioServiceClassInfo )
    867 {
    868 	DEBUG_UNUSED( inProviderID );
    869 	DEBUG_UNUSED( ioSize );
    870 	DEBUG_UNUSED( ioServiceClassInfo );
    871 
    872 	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    873 	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
    874 
    875 	// We don't allow service classes to be installed so always return an error.
    876 
    877 	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
    878 	return( WSATYPE_NOT_FOUND );
    879 }
    880 
    881 #if 0
    882 #pragma mark -
    883 #endif
    884 
    885 //===========================================================================================================================
    886 //	QueryCreate
    887 //
    888 //	Warning: Assumes the NSP lock is held.
    889 //===========================================================================================================================
    890 
    891 DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef )
    892 {
    893 	OSStatus		err;
    894 	QueryRef		obj;
    895 	char			name[ kDNSServiceMaxDomainName ];
    896 	int				n;
    897 	QueryRef *		p;
    898 	SOCKET			s4;
    899 	SOCKET			s6;
    900 
    901 	obj = NULL;
    902 	check( inQuerySet );
    903 	check( inQuerySet->lpszServiceInstanceName );
    904 	check( outRef );
    905 
    906 	// Convert the wchar_t name to UTF-8.
    907 
    908 	n = WideCharToMultiByte( CP_UTF8, 0, inQuerySet->lpszServiceInstanceName, -1, name, sizeof( name ), NULL, NULL );
    909 	err = translate_errno( n > 0, (OSStatus) GetLastError(), WSAEINVAL );
    910 	require_noerr( err, exit );
    911 
    912 	// Allocate the object and append it to the list. Append immediately so releases of partial objects work.
    913 
    914 	obj = (QueryRef) calloc( 1, sizeof( *obj ) );
    915 	require_action( obj, exit, err = WSA_NOT_ENOUGH_MEMORY );
    916 
    917 	obj->refCount = 1;
    918 
    919 	for( p = &gQueryList; *p; p = &( *p )->next ) {}	// Find the end of the list.
    920 	*p = obj;
    921 
    922 	// Set up cancel event
    923 
    924 	obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    925 	require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
    926 
    927 	// Set up events to signal when A record data is ready
    928 
    929 	obj->data4Event = CreateEvent( NULL, TRUE, FALSE, NULL );
    930 	require_action( obj->data4Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
    931 
    932 	// Start the query.  Handle delay loaded DLL errors.
    933 
    934 	__try
    935 	{
    936 		err = DNSServiceQueryRecord( &obj->resolver4, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordCallback4, obj );
    937 	}
    938 	__except( EXCEPTION_EXECUTE_HANDLER )
    939 	{
    940 		err = kUnknownErr;
    941 	}
    942 
    943 	require_noerr( err, exit );
    944 
    945 	// Attach the socket to the event
    946 
    947 	__try
    948 	{
    949 		s4 = DNSServiceRefSockFD(obj->resolver4);
    950 	}
    951 	__except( EXCEPTION_EXECUTE_HANDLER )
    952 	{
    953 		s4 = INVALID_SOCKET;
    954 	}
    955 
    956 	err = translate_errno( s4 != INVALID_SOCKET, errno_compat(), kUnknownErr );
    957 	require_noerr( err, exit );
    958 
    959 	WSAEventSelect(s4, obj->data4Event, FD_READ|FD_CLOSE);
    960 
    961 	// Set up events to signal when AAAA record data is ready
    962 
    963 	obj->data6Event = CreateEvent( NULL, TRUE, FALSE, NULL );
    964 	require_action( obj->data6Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
    965 
    966 	// Start the query.  Handle delay loaded DLL errors.
    967 
    968 	__try
    969 	{
    970 		err = DNSServiceQueryRecord( &obj->resolver6, 0, 0, name, kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordCallback6, obj );
    971 	}
    972 	__except( EXCEPTION_EXECUTE_HANDLER )
    973 	{
    974 		err = kUnknownErr;
    975 	}
    976 
    977 	require_noerr( err, exit );
    978 
    979 	// Attach the socket to the event
    980 
    981 	__try
    982 	{
    983 		s6 = DNSServiceRefSockFD(obj->resolver6);
    984 	}
    985 	__except( EXCEPTION_EXECUTE_HANDLER )
    986 	{
    987 		s6 = INVALID_SOCKET;
    988 	}
    989 
    990 	err = translate_errno( s6 != INVALID_SOCKET, errno_compat(), kUnknownErr );
    991 	require_noerr( err, exit );
    992 
    993 	WSAEventSelect(s6, obj->data6Event, FD_READ|FD_CLOSE);
    994 
    995 	obj->waitCount = 0;
    996 	obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
    997 	obj->waitHandles[ obj->waitCount++ ] = obj->data4Event;
    998 	obj->waitHandles[ obj->waitCount++ ] = obj->data6Event;
    999 
   1000 	check( obj->waitCount == sizeof_array( obj->waitHandles ) );
   1001 
   1002 	// Copy the QuerySet so it can be returned later.
   1003 
   1004 	obj->querySetFlags = inQuerySetFlags;
   1005 	inQuerySetFlags = ( inQuerySetFlags & ~( LUP_RETURN_ADDR | LUP_RETURN_BLOB ) ) | LUP_RETURN_NAME;
   1006 	err = QueryCopyQuerySet( obj, inQuerySet, inQuerySetFlags, &obj->querySet, &obj->querySetSize );
   1007 	require_noerr( err, exit );
   1008 
   1009 	// Success!
   1010 
   1011 	*outRef	= obj;
   1012 	obj 	= NULL;
   1013 	err 	= NO_ERROR;
   1014 
   1015 exit:
   1016 	if( obj )
   1017 	{
   1018 		QueryRelease( obj );
   1019 	}
   1020 	return( err );
   1021 }
   1022 
   1023 //===========================================================================================================================
   1024 //	QueryRetain
   1025 //
   1026 //	Warning: Assumes the NSP lock is held.
   1027 //===========================================================================================================================
   1028 
   1029 DEBUG_LOCAL OSStatus	QueryRetain( QueryRef inRef )
   1030 {
   1031 	OSStatus		err;
   1032 	QueryRef		obj;
   1033 
   1034 	for( obj = gQueryList; obj; obj = obj->next )
   1035 	{
   1036 		if( obj == inRef )
   1037 		{
   1038 			break;
   1039 		}
   1040 	}
   1041 	require_action( obj, exit, err = WSA_INVALID_HANDLE );
   1042 
   1043 	++inRef->refCount;
   1044 	err = NO_ERROR;
   1045 
   1046 exit:
   1047 	return( err );
   1048 }
   1049 
   1050 //===========================================================================================================================
   1051 //	QueryRelease
   1052 //
   1053 //	Warning: Assumes the NSP lock is held.
   1054 //===========================================================================================================================
   1055 
   1056 DEBUG_LOCAL OSStatus	QueryRelease( QueryRef inRef )
   1057 {
   1058 	OSStatus		err;
   1059 	QueryRef *		p;
   1060 	BOOL			ok;
   1061 
   1062 	// Find the item in the list.
   1063 
   1064 	for( p = &gQueryList; *p; p = &( *p )->next )
   1065 	{
   1066 		if( *p == inRef )
   1067 		{
   1068 			break;
   1069 		}
   1070 	}
   1071 	require_action( *p, exit, err = WSA_INVALID_HANDLE );
   1072 
   1073 	// Signal a cancel to unblock any threads waiting for results.
   1074 
   1075 	if( inRef->cancelEvent )
   1076 	{
   1077 		ok = SetEvent( inRef->cancelEvent );
   1078 		check_translated_errno( ok, GetLastError(), WSAEINVAL );
   1079 	}
   1080 
   1081 	// Stop the query.
   1082 
   1083 	if( inRef->resolver4 )
   1084 	{
   1085 		__try
   1086 		{
   1087 			DNSServiceRefDeallocate( inRef->resolver4 );
   1088 		}
   1089 		__except( EXCEPTION_EXECUTE_HANDLER )
   1090 		{
   1091 		}
   1092 
   1093 		inRef->resolver4 = NULL;
   1094 	}
   1095 
   1096 	if ( inRef->resolver6 )
   1097 	{
   1098 		__try
   1099 		{
   1100 			DNSServiceRefDeallocate( inRef->resolver6 );
   1101 		}
   1102 		__except( EXCEPTION_EXECUTE_HANDLER )
   1103 		{
   1104 		}
   1105 
   1106 		inRef->resolver6 = NULL;
   1107 	}
   1108 
   1109 	// Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
   1110 
   1111 	if( --inRef->refCount != 0 )
   1112 	{
   1113 		err = NO_ERROR;
   1114 		goto exit;
   1115 	}
   1116 	*p = inRef->next;
   1117 
   1118 	// Release resources.
   1119 
   1120 	if( inRef->cancelEvent )
   1121 	{
   1122 		ok = CloseHandle( inRef->cancelEvent );
   1123 		check_translated_errno( ok, GetLastError(), WSAEINVAL );
   1124 	}
   1125 	if( inRef->data4Event )
   1126 	{
   1127 		ok = CloseHandle( inRef->data4Event );
   1128 		check_translated_errno( ok, GetLastError(), WSAEINVAL );
   1129 	}
   1130 	if( inRef->data6Event )
   1131 	{
   1132 		ok = CloseHandle( inRef->data6Event );
   1133 		check_translated_errno( ok, GetLastError(), WSAEINVAL );
   1134 	}
   1135 	if( inRef->querySet )
   1136 	{
   1137 		free( inRef->querySet );
   1138 	}
   1139 	free( inRef );
   1140 	err = NO_ERROR;
   1141 
   1142 exit:
   1143 	return( err );
   1144 }
   1145 
   1146 //===========================================================================================================================
   1147 //	QueryRecordCallback4
   1148 //===========================================================================================================================
   1149 
   1150 DEBUG_LOCAL void CALLBACK_COMPAT
   1151 	QueryRecordCallback4(
   1152 		DNSServiceRef		inRef,
   1153 		DNSServiceFlags		inFlags,
   1154 		uint32_t			inInterfaceIndex,
   1155 		DNSServiceErrorType	inErrorCode,
   1156 		const char *		inName,
   1157 		uint16_t			inRRType,
   1158 		uint16_t			inRRClass,
   1159 		uint16_t			inRDataSize,
   1160 		const void *		inRData,
   1161 		uint32_t			inTTL,
   1162 		void *				inContext )
   1163 {
   1164 	QueryRef			obj;
   1165 	const char *		src;
   1166 	char *				dst;
   1167 	BOOL				ok;
   1168 
   1169 	DEBUG_UNUSED( inFlags );
   1170 	DEBUG_UNUSED( inInterfaceIndex );
   1171 	DEBUG_UNUSED( inTTL );
   1172 
   1173 	NSPLock();
   1174 	obj = (QueryRef) inContext;
   1175 	check( obj );
   1176 	require_noerr( inErrorCode, exit );
   1177 	require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
   1178 	require( inRRClass   == kDNSServiceClass_IN, exit );
   1179 	require( inRRType    == kDNSServiceType_A, exit );
   1180 	require( inRDataSize == 4, exit );
   1181 
   1182 	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
   1183 		__ROUTINE__, inFlags, inName, inRRType, inRDataSize );
   1184 
   1185 	// Copy the name if needed.
   1186 
   1187 	if( obj->name[ 0 ] == '\0' )
   1188 	{
   1189 		src = inName;
   1190 		dst = obj->name;
   1191 		while( *src != '\0' )
   1192 		{
   1193 			*dst++ = *src++;
   1194 		}
   1195 		*dst = '\0';
   1196 		obj->nameSize = (size_t)( dst - obj->name );
   1197 		check( obj->nameSize < sizeof( obj->name ) );
   1198 	}
   1199 
   1200 	// Copy the data.
   1201 
   1202 	memcpy( &obj->addr4, inRData, inRDataSize );
   1203 	obj->addr4Valid = true;
   1204 	obj->numValidAddrs++;
   1205 
   1206 	// Signal that a result is ready.
   1207 
   1208 	check( obj->data4Event );
   1209 	ok = SetEvent( obj->data4Event );
   1210 	check_translated_errno( ok, GetLastError(), WSAEINVAL );
   1211 
   1212 	// Stop the resolver after the first response.
   1213 
   1214 	__try
   1215 	{
   1216 		DNSServiceRefDeallocate( inRef );
   1217 	}
   1218 	__except( EXCEPTION_EXECUTE_HANDLER )
   1219 	{
   1220 	}
   1221 
   1222 	obj->resolver4 = NULL;
   1223 
   1224 exit:
   1225 	NSPUnlock();
   1226 }
   1227 
   1228 #if 0
   1229 #pragma mark -
   1230 #endif
   1231 
   1232 
   1233 //===========================================================================================================================
   1234 //	QueryRecordCallback6
   1235 //===========================================================================================================================
   1236 
   1237 DEBUG_LOCAL void CALLBACK_COMPAT
   1238 	QueryRecordCallback6(
   1239 		DNSServiceRef		inRef,
   1240 		DNSServiceFlags		inFlags,
   1241 		uint32_t			inInterfaceIndex,
   1242 		DNSServiceErrorType	inErrorCode,
   1243 		const char *		inName,
   1244 		uint16_t			inRRType,
   1245 		uint16_t			inRRClass,
   1246 		uint16_t			inRDataSize,
   1247 		const void *		inRData,
   1248 		uint32_t			inTTL,
   1249 		void *				inContext )
   1250 {
   1251 	QueryRef			obj;
   1252 	const char *		src;
   1253 	char *				dst;
   1254 	BOOL				ok;
   1255 
   1256 	DEBUG_UNUSED( inFlags );
   1257 	DEBUG_UNUSED( inInterfaceIndex );
   1258 	DEBUG_UNUSED( inTTL );
   1259 
   1260 	NSPLock();
   1261 	obj = (QueryRef) inContext;
   1262 	check( obj );
   1263 	require_noerr( inErrorCode, exit );
   1264 	require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
   1265 	require( inRRClass   == kDNSServiceClass_IN, exit );
   1266 	require( inRRType    == kDNSServiceType_AAAA, exit );
   1267 	require( inRDataSize == 16, exit );
   1268 
   1269 	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
   1270 		__ROUTINE__, inFlags, inName, inRRType, inRDataSize );
   1271 
   1272 	// Copy the name if needed.
   1273 
   1274 	if( obj->name[ 0 ] == '\0' )
   1275 	{
   1276 		src = inName;
   1277 		dst = obj->name;
   1278 		while( *src != '\0' )
   1279 		{
   1280 			*dst++ = *src++;
   1281 		}
   1282 		*dst = '\0';
   1283 		obj->nameSize = (size_t)( dst - obj->name );
   1284 		check( obj->nameSize < sizeof( obj->name ) );
   1285 	}
   1286 
   1287 	// Copy the data.
   1288 
   1289 	memcpy( &obj->addr6, inRData, inRDataSize );
   1290 
   1291 	obj->addr6ScopeId = GetScopeId( inInterfaceIndex );
   1292 	require( obj->addr6ScopeId, exit );
   1293 	obj->addr6Valid	  = true;
   1294 	obj->numValidAddrs++;
   1295 
   1296 	// Signal that we're done
   1297 
   1298 	check( obj->data6Event );
   1299 	ok = SetEvent( obj->data6Event );
   1300 	check_translated_errno( ok, GetLastError(), WSAEINVAL );
   1301 
   1302 	// Stop the resolver after the first response.
   1303 
   1304 	__try
   1305 	{
   1306 		DNSServiceRefDeallocate( inRef );
   1307 	}
   1308 	__except( EXCEPTION_EXECUTE_HANDLER )
   1309 	{
   1310 	}
   1311 
   1312 	obj->resolver6 = NULL;
   1313 
   1314 exit:
   1315 
   1316 
   1317 
   1318 	NSPUnlock();
   1319 }
   1320 
   1321 
   1322 //===========================================================================================================================
   1323 //	QueryCopyQuerySet
   1324 //
   1325 //	Warning: Assumes the NSP lock is held.
   1326 //===========================================================================================================================
   1327 
   1328 DEBUG_LOCAL OSStatus
   1329 	QueryCopyQuerySet(
   1330 		QueryRef 				inRef,
   1331 		const WSAQUERYSETW *	inQuerySet,
   1332 		DWORD 					inQuerySetFlags,
   1333 		WSAQUERYSETW **			outQuerySet,
   1334 		size_t *				outSize )
   1335 {
   1336 	OSStatus			err;
   1337 	size_t				size;
   1338 	WSAQUERYSETW *		qs;
   1339 
   1340 	check( inQuerySet );
   1341 	check( outQuerySet );
   1342 
   1343 	size  = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
   1344 	qs = (WSAQUERYSETW *) calloc( 1, size );
   1345 	require_action( qs, exit, err = WSA_NOT_ENOUGH_MEMORY  );
   1346 
   1347 	QueryCopyQuerySetTo( inRef, inQuerySet, inQuerySetFlags, qs );
   1348 
   1349 	*outQuerySet = qs;
   1350 	if( outSize )
   1351 	{
   1352 		*outSize = size;
   1353 	}
   1354 	qs = NULL;
   1355 	err = NO_ERROR;
   1356 
   1357 exit:
   1358 	if( qs )
   1359 	{
   1360 		free( qs );
   1361 	}
   1362 	return( err );
   1363 }
   1364 
   1365 
   1366 
   1367 //===========================================================================================================================
   1368 //	QueryCopyQuerySetTo
   1369 //
   1370 //	Warning: Assumes the NSP lock is held.
   1371 //===========================================================================================================================
   1372 
   1373 DEBUG_LOCAL void
   1374 	QueryCopyQuerySetTo(
   1375 		QueryRef 				inRef,
   1376 		const WSAQUERYSETW *	inQuerySet,
   1377 		DWORD 					inQuerySetFlags,
   1378 		WSAQUERYSETW *			outQuerySet )
   1379 {
   1380 	uint8_t *		dst;
   1381 	LPCWSTR			s;
   1382 	LPWSTR			q;
   1383 	DWORD			n;
   1384 	DWORD			i;
   1385 
   1386 #if( DEBUG )
   1387 	size_t			debugSize;
   1388 
   1389 	debugSize = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
   1390 #endif
   1391 
   1392 	check( inQuerySet );
   1393 	check( outQuerySet );
   1394 
   1395 	dst = (uint8_t *) outQuerySet;
   1396 
   1397 	// Copy the static portion of the results.
   1398 
   1399 	*outQuerySet = *inQuerySet;
   1400 	dst += sizeof( *inQuerySet );
   1401 
   1402 	if( inQuerySetFlags & LUP_RETURN_NAME )
   1403 	{
   1404 		s = inQuerySet->lpszServiceInstanceName;
   1405 		if( s )
   1406 		{
   1407 			outQuerySet->lpszServiceInstanceName = (LPWSTR) dst;
   1408 			q = (LPWSTR) dst;
   1409 			while( ( *q++ = *s++ ) != 0 ) {}
   1410 			dst = (uint8_t *) q;
   1411 		}
   1412 	}
   1413 	else
   1414 	{
   1415 		outQuerySet->lpszServiceInstanceName = NULL;
   1416 	}
   1417 
   1418 	if( inQuerySet->lpServiceClassId )
   1419 	{
   1420 		outQuerySet->lpServiceClassId  = (LPGUID) dst;
   1421 		*outQuerySet->lpServiceClassId = *inQuerySet->lpServiceClassId;
   1422 		dst += sizeof( *inQuerySet->lpServiceClassId );
   1423 	}
   1424 
   1425 	if( inQuerySet->lpVersion )
   1426 	{
   1427 		outQuerySet->lpVersion  = (LPWSAVERSION) dst;
   1428 		*outQuerySet->lpVersion = *inQuerySet->lpVersion;
   1429 		dst += sizeof( *inQuerySet->lpVersion );
   1430 	}
   1431 
   1432 	s = inQuerySet->lpszComment;
   1433 	if( s )
   1434 	{
   1435 		outQuerySet->lpszComment = (LPWSTR) dst;
   1436 		q = (LPWSTR) dst;
   1437 		while( ( *q++ = *s++ ) != 0 ) {}
   1438 		dst = (uint8_t *) q;
   1439 	}
   1440 
   1441 	if( inQuerySet->lpNSProviderId )
   1442 	{
   1443 		outQuerySet->lpNSProviderId  = (LPGUID) dst;
   1444 		*outQuerySet->lpNSProviderId = *inQuerySet->lpNSProviderId;
   1445 		dst += sizeof( *inQuerySet->lpNSProviderId );
   1446 	}
   1447 
   1448 	s = inQuerySet->lpszContext;
   1449 	if( s )
   1450 	{
   1451 		outQuerySet->lpszContext = (LPWSTR) dst;
   1452 		q = (LPWSTR) dst;
   1453 		while( ( *q++ = *s++ ) != 0 ) {}
   1454 		dst = (uint8_t *) q;
   1455 	}
   1456 
   1457 	n = inQuerySet->dwNumberOfProtocols;
   1458 
   1459 	if( n > 0 )
   1460 	{
   1461 		check( inQuerySet->lpafpProtocols );
   1462 
   1463 		outQuerySet->lpafpProtocols = (LPAFPROTOCOLS) dst;
   1464 		for( i = 0; i < n; ++i )
   1465 		{
   1466 			outQuerySet->lpafpProtocols[ i ] = inQuerySet->lpafpProtocols[ i ];
   1467 			dst += sizeof( *inQuerySet->lpafpProtocols );
   1468 		}
   1469 	}
   1470 
   1471 	s = inQuerySet->lpszQueryString;
   1472 	if( s )
   1473 	{
   1474 		outQuerySet->lpszQueryString = (LPWSTR) dst;
   1475 		q = (LPWSTR) dst;
   1476 		while( ( *q++ = *s++ ) != 0 ) {}
   1477 		dst = (uint8_t *) q;
   1478 	}
   1479 
   1480 	// Copy the address(es).
   1481 
   1482 	if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && ( inRef->numValidAddrs > 0 ) )
   1483 	{
   1484 		struct sockaddr_in	*	addr4;
   1485 		struct sockaddr_in6	*	addr6;
   1486 		int						index;
   1487 
   1488 		outQuerySet->dwNumberOfCsAddrs	= inRef->numValidAddrs;
   1489 		outQuerySet->lpcsaBuffer 		= (LPCSADDR_INFO) dst;
   1490 		dst 							+= ( sizeof( *outQuerySet->lpcsaBuffer ) ) * ( inRef->numValidAddrs ) ;
   1491 		index							= 0;
   1492 
   1493 		if ( inRef->addr4Valid )
   1494 		{
   1495 			outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr 			= NULL;
   1496 			outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength		= 0;
   1497 
   1498 			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr 		= (LPSOCKADDR) dst;
   1499 			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength	= sizeof( struct sockaddr_in );
   1500 
   1501 			addr4 															= (struct sockaddr_in *) dst;
   1502 			memset( addr4, 0, sizeof( *addr4 ) );
   1503 			addr4->sin_family												= AF_INET;
   1504 			memcpy( &addr4->sin_addr, &inRef->addr4, 4 );
   1505 			dst 															+= sizeof( *addr4 );
   1506 
   1507 			outQuerySet->lpcsaBuffer[ index ].iSocketType 					= AF_INET;		// Emulate Tcpip NSP
   1508 			outQuerySet->lpcsaBuffer[ index ].iProtocol						= IPPROTO_UDP;	// Emulate Tcpip NSP
   1509 
   1510 			index++;
   1511 		}
   1512 
   1513 		if ( inRef->addr6Valid )
   1514 		{
   1515 			outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr 			= NULL;
   1516 			outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength		= 0;
   1517 
   1518 			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr 		= (LPSOCKADDR) dst;
   1519 			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength	= sizeof( struct sockaddr_in6 );
   1520 
   1521 			addr6 															= (struct sockaddr_in6 *) dst;
   1522 			memset( addr6, 0, sizeof( *addr6 ) );
   1523 			addr6->sin6_family												= AF_INET6;
   1524 			addr6->sin6_scope_id											= inRef->addr6ScopeId;
   1525 			memcpy( &addr6->sin6_addr, &inRef->addr6, 16 );
   1526 			dst 															+= sizeof( *addr6 );
   1527 
   1528 			outQuerySet->lpcsaBuffer[ index ].iSocketType 					= AF_INET6;		// Emulate Tcpip NSP
   1529 			outQuerySet->lpcsaBuffer[ index ].iProtocol						= IPPROTO_UDP;	// Emulate Tcpip NSP
   1530 		}
   1531 	}
   1532 	else
   1533 	{
   1534 		outQuerySet->dwNumberOfCsAddrs	= 0;
   1535 		outQuerySet->lpcsaBuffer 		= NULL;
   1536 	}
   1537 
   1538 	// Copy the hostent blob.
   1539 
   1540 	if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
   1541 	{
   1542 		uint8_t *				base;
   1543 		struct hostent *		he;
   1544 		uintptr_t *				p;
   1545 
   1546 		outQuerySet->lpBlob	 = (LPBLOB) dst;
   1547 		dst 				+= sizeof( *outQuerySet->lpBlob );
   1548 
   1549 		base = dst;
   1550 		he	 = (struct hostent *) dst;
   1551 		dst += sizeof( *he );
   1552 
   1553 		he->h_name = (char *)( dst - base );
   1554 		memcpy( dst, inRef->name, inRef->nameSize + 1 );
   1555 		dst += ( inRef->nameSize + 1 );
   1556 
   1557 		he->h_aliases 	= (char **)( dst - base );
   1558 		p	  			= (uintptr_t *) dst;
   1559 		*p++  			= 0;
   1560 		dst 		 	= (uint8_t *) p;
   1561 
   1562 		he->h_addrtype 	= AF_INET;
   1563 		he->h_length	= 4;
   1564 
   1565 		he->h_addr_list	= (char **)( dst - base );
   1566 		p	  			= (uintptr_t *) dst;
   1567 		dst 		   += ( 2 * sizeof( *p ) );
   1568 		*p++			= (uintptr_t)( dst - base );
   1569 		*p++			= 0;
   1570 		p	  			= (uintptr_t *) dst;
   1571 		*p++			= (uintptr_t) inRef->addr4;
   1572 		dst 		 	= (uint8_t *) p;
   1573 
   1574 		outQuerySet->lpBlob->cbSize 	= (ULONG)( dst - base );
   1575 		outQuerySet->lpBlob->pBlobData	= (BYTE *) base;
   1576 	}
   1577 	dlog_query_set( kDebugLevelVerbose, outQuerySet );
   1578 
   1579 	check( (size_t)( dst - ( (uint8_t *) outQuerySet ) ) == debugSize );
   1580 }
   1581 
   1582 //===========================================================================================================================
   1583 //	QueryCopyQuerySetSize
   1584 //
   1585 //	Warning: Assumes the NSP lock is held.
   1586 //===========================================================================================================================
   1587 
   1588 DEBUG_LOCAL size_t	QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags )
   1589 {
   1590 	size_t		size;
   1591 	LPCWSTR		s;
   1592 	LPCWSTR		p;
   1593 
   1594 	check( inRef );
   1595 	check( inQuerySet );
   1596 
   1597 	// Calculate the size of the static portion of the results.
   1598 
   1599 	size = sizeof( *inQuerySet );
   1600 
   1601 	if( inQuerySetFlags & LUP_RETURN_NAME )
   1602 	{
   1603 		s = inQuerySet->lpszServiceInstanceName;
   1604 		if( s )
   1605 		{
   1606 			for( p = s; *p; ++p ) {}
   1607 			size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
   1608 		}
   1609 	}
   1610 
   1611 	if( inQuerySet->lpServiceClassId )
   1612 	{
   1613 		size += sizeof( *inQuerySet->lpServiceClassId );
   1614 	}
   1615 
   1616 	if( inQuerySet->lpVersion )
   1617 	{
   1618 		size += sizeof( *inQuerySet->lpVersion );
   1619 	}
   1620 
   1621 	s = inQuerySet->lpszComment;
   1622 	if( s )
   1623 	{
   1624 		for( p = s; *p; ++p ) {}
   1625 		size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
   1626 	}
   1627 
   1628 	if( inQuerySet->lpNSProviderId )
   1629 	{
   1630 		size += sizeof( *inQuerySet->lpNSProviderId );
   1631 	}
   1632 
   1633 	s = inQuerySet->lpszContext;
   1634 	if( s )
   1635 	{
   1636 		for( p = s; *p; ++p ) {}
   1637 		size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
   1638 	}
   1639 
   1640 	size += ( inQuerySet->dwNumberOfProtocols * sizeof( *inQuerySet->lpafpProtocols ) );
   1641 
   1642 	s = inQuerySet->lpszQueryString;
   1643 	if( s )
   1644 	{
   1645 		for( p = s; *p; ++p ) {}
   1646 		size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
   1647 	}
   1648 
   1649 	// Calculate the size of the address(es).
   1650 
   1651 	if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr4Valid )
   1652 	{
   1653 		size += sizeof( *inQuerySet->lpcsaBuffer );
   1654 		size += sizeof( struct sockaddr_in );
   1655 	}
   1656 
   1657 	if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr6Valid )
   1658 	{
   1659 		size += sizeof( *inQuerySet->lpcsaBuffer );
   1660 		size += sizeof( struct sockaddr_in6 );
   1661 	}
   1662 
   1663 	// Calculate the size of the hostent blob.
   1664 
   1665 	if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
   1666 	{
   1667 		size += sizeof( *inQuerySet->lpBlob );	// Blob ptr/size structure
   1668 		size += sizeof( struct hostent );		// Old-style hostent structure
   1669 		size += ( inRef->nameSize + 1 );		// Name and null terminator
   1670 		size += 4;								// Alias list terminator (0 offset)
   1671 		size += 4;								// Offset to address.
   1672 		size += 4;								// Address list terminator (0 offset)
   1673 		size += 4;								// IPv4 address
   1674 	}
   1675 	return( size );
   1676 }
   1677 
   1678 #if 0
   1679 #pragma mark -
   1680 #endif
   1681 
   1682 #if( DEBUG )
   1683 //===========================================================================================================================
   1684 //	DebugDumpQuerySet
   1685 //===========================================================================================================================
   1686 
   1687 #define	DebugSocketFamilyToString( FAM )	( ( FAM ) == AF_INET )  ? "AF_INET"  : \
   1688 											( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
   1689 
   1690 #define	DebugSocketProtocolToString( PROTO )	( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
   1691 												( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
   1692 
   1693 #define	DebugNameSpaceToString( NS )			( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
   1694 
   1695 void	DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet )
   1696 {
   1697 	DWORD		i;
   1698 
   1699 	check( inQuerySet );
   1700 
   1701 	// Fixed portion of the QuerySet.
   1702 
   1703 	dlog( inLevel, "QuerySet:\n" );
   1704 	dlog( inLevel, "    dwSize:                  %d (expected %d)\n", inQuerySet->dwSize, sizeof( *inQuerySet ) );
   1705 	if( inQuerySet->lpszServiceInstanceName )
   1706 	{
   1707 		dlog( inLevel, "    lpszServiceInstanceName: %S\n", inQuerySet->lpszServiceInstanceName );
   1708 	}
   1709 	else
   1710 	{
   1711 		dlog( inLevel, "    lpszServiceInstanceName: <null>\n" );
   1712 	}
   1713 	if( inQuerySet->lpServiceClassId )
   1714 	{
   1715 		dlog( inLevel, "    lpServiceClassId:        %U\n", inQuerySet->lpServiceClassId );
   1716 	}
   1717 	else
   1718 	{
   1719 		dlog( inLevel, "    lpServiceClassId:        <null>\n" );
   1720 	}
   1721 	if( inQuerySet->lpVersion )
   1722 	{
   1723 		dlog( inLevel, "    lpVersion:\n" );
   1724 		dlog( inLevel, "        dwVersion:               %d\n", inQuerySet->lpVersion->dwVersion );
   1725 		dlog( inLevel, "        dwVersion:               %d\n", inQuerySet->lpVersion->ecHow );
   1726 	}
   1727 	else
   1728 	{
   1729 		dlog( inLevel, "    lpVersion:               <null>\n" );
   1730 	}
   1731 	if( inQuerySet->lpszComment )
   1732 	{
   1733 		dlog( inLevel, "    lpszComment:             %S\n", inQuerySet->lpszComment );
   1734 	}
   1735 	else
   1736 	{
   1737 		dlog( inLevel, "    lpszComment:             <null>\n" );
   1738 	}
   1739 	dlog( inLevel, "    dwNameSpace:             %d %s\n", inQuerySet->dwNameSpace,
   1740 		DebugNameSpaceToString( inQuerySet->dwNameSpace ) );
   1741 	if( inQuerySet->lpNSProviderId )
   1742 	{
   1743 		dlog( inLevel, "    lpNSProviderId:          %U\n", inQuerySet->lpNSProviderId );
   1744 	}
   1745 	else
   1746 	{
   1747 		dlog( inLevel, "    lpNSProviderId:          <null>\n" );
   1748 	}
   1749 	if( inQuerySet->lpszContext )
   1750 	{
   1751 		dlog( inLevel, "    lpszContext:             %S\n", inQuerySet->lpszContext );
   1752 	}
   1753 	else
   1754 	{
   1755 		dlog( inLevel, "    lpszContext:             <null>\n" );
   1756 	}
   1757 	dlog( inLevel, "    dwNumberOfProtocols:     %d\n", inQuerySet->dwNumberOfProtocols );
   1758 	dlog( inLevel, "    lpafpProtocols:          %s\n", inQuerySet->lpafpProtocols ? "" : "<null>" );
   1759 	for( i = 0; i < inQuerySet->dwNumberOfProtocols; ++i )
   1760 	{
   1761 		if( i != 0 )
   1762 		{
   1763 			dlog( inLevel, "\n" );
   1764 		}
   1765 		dlog( inLevel, "        iAddressFamily:          %d %s\n", inQuerySet->lpafpProtocols[ i ].iAddressFamily,
   1766 			DebugSocketFamilyToString( inQuerySet->lpafpProtocols[ i ].iAddressFamily ) );
   1767 		dlog( inLevel, "        iProtocol:               %d %s\n", inQuerySet->lpafpProtocols[ i ].iProtocol,
   1768 			DebugSocketProtocolToString( inQuerySet->lpafpProtocols[ i ].iProtocol ) );
   1769 	}
   1770 	if( inQuerySet->lpszQueryString )
   1771 	{
   1772 		dlog( inLevel, "    lpszQueryString:         %S\n", inQuerySet->lpszQueryString );
   1773 	}
   1774 	else
   1775 	{
   1776 		dlog( inLevel, "    lpszQueryString:         <null>\n" );
   1777 	}
   1778 	dlog( inLevel, "    dwNumberOfCsAddrs:       %d\n", inQuerySet->dwNumberOfCsAddrs );
   1779 	dlog( inLevel, "    lpcsaBuffer:             %s\n", inQuerySet->lpcsaBuffer ? "" : "<null>" );
   1780 	for( i = 0; i < inQuerySet->dwNumberOfCsAddrs; ++i )
   1781 	{
   1782 		if( i != 0 )
   1783 		{
   1784 			dlog( inLevel, "\n" );
   1785 		}
   1786 		if( inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr &&
   1787 			( inQuerySet->lpcsaBuffer[ i ].LocalAddr.iSockaddrLength > 0 ) )
   1788 		{
   1789 			dlog( inLevel, "        LocalAddr:               %##a\n",
   1790 				inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr );
   1791 		}
   1792 		else
   1793 		{
   1794 			dlog( inLevel, "        LocalAddr:               <null/empty>\n" );
   1795 		}
   1796 		if( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr &&
   1797 			( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.iSockaddrLength > 0 ) )
   1798 		{
   1799 			dlog( inLevel, "        RemoteAddr:              %##a\n",
   1800 				inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr );
   1801 		}
   1802 		else
   1803 		{
   1804 			dlog( inLevel, "        RemoteAddr:              <null/empty>\n" );
   1805 		}
   1806 		dlog( inLevel, "        iSocketType:             %d\n", inQuerySet->lpcsaBuffer[ i ].iSocketType );
   1807 		dlog( inLevel, "        iProtocol:               %d\n", inQuerySet->lpcsaBuffer[ i ].iProtocol );
   1808 	}
   1809 	dlog( inLevel, "    dwOutputFlags:           %d\n", inQuerySet->dwOutputFlags );
   1810 
   1811 	// Blob portion of the QuerySet.
   1812 
   1813 	if( inQuerySet->lpBlob )
   1814 	{
   1815 		dlog( inLevel, "    lpBlob:\n" );
   1816 		dlog( inLevel, "        cbSize:                  %ld\n", inQuerySet->lpBlob->cbSize );
   1817 		dlog( inLevel, "        pBlobData:               %#p\n", inQuerySet->lpBlob->pBlobData );
   1818 		dloghex( inLevel, 12, NULL, 0, 0, NULL, 0,
   1819 			inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->cbSize,
   1820 			kDebugFlagsNone, NULL, 0 );
   1821 	}
   1822 	else
   1823 	{
   1824 		dlog( inLevel, "    lpBlob:                  <null>\n" );
   1825 	}
   1826 }
   1827 #endif
   1828 
   1829 
   1830 //===========================================================================================================================
   1831 //	InHostsTable
   1832 //===========================================================================================================================
   1833 
   1834 DEBUG_LOCAL BOOL
   1835 InHostsTable( const char * name )
   1836 {
   1837 	HostsFileInfo	*	node;
   1838 	BOOL				ret = FALSE;
   1839 	OSStatus			err;
   1840 
   1841 	check( name );
   1842 
   1843 	if ( gHostsFileInfo == NULL )
   1844 	{
   1845 		TCHAR				systemDirectory[MAX_PATH];
   1846 		TCHAR				hFileName[MAX_PATH];
   1847 		HostsFile		*	hFile;
   1848 
   1849 		GetSystemDirectory( systemDirectory, sizeof( systemDirectory ) );
   1850 		sprintf( hFileName, "%s\\drivers\\etc\\hosts", systemDirectory );
   1851 		err = HostsFileOpen( &hFile, hFileName );
   1852 		require_noerr( err, exit );
   1853 
   1854 		while ( HostsFileNext( hFile, &node ) == 0 )
   1855 		{
   1856 			if ( IsLocalName( node ) )
   1857 			{
   1858 				node->m_next = gHostsFileInfo;
   1859 				gHostsFileInfo = node;
   1860 			}
   1861 			else
   1862 			{
   1863 				HostsFileInfoFree( node );
   1864 			}
   1865 		}
   1866 
   1867 		HostsFileClose( hFile );
   1868 	}
   1869 
   1870 	for ( node = gHostsFileInfo; node; node = node->m_next )
   1871 	{
   1872 		if ( IsSameName( node, name ) )
   1873 		{
   1874 			ret = TRUE;
   1875 			break;
   1876 		}
   1877 	}
   1878 
   1879 exit:
   1880 
   1881 	return ret;
   1882 }
   1883 
   1884 
   1885 //===========================================================================================================================
   1886 //	IsLocalName
   1887 //===========================================================================================================================
   1888 
   1889 DEBUG_LOCAL BOOL
   1890 IsLocalName( HostsFileInfo * node )
   1891 {
   1892 	BOOL ret = TRUE;
   1893 
   1894 	check( node );
   1895 
   1896 	if ( strstr( node->m_host.h_name, ".local" ) == NULL )
   1897 	{
   1898 		int i;
   1899 
   1900 		for ( i = 0; node->m_host.h_aliases[i]; i++ )
   1901 		{
   1902 			if ( strstr( node->m_host.h_aliases[i], ".local" ) )
   1903 			{
   1904 				goto exit;
   1905 			}
   1906 		}
   1907 
   1908 		ret = FALSE;
   1909 	}
   1910 
   1911 exit:
   1912 
   1913 	return ret;
   1914 }
   1915 
   1916 
   1917 //===========================================================================================================================
   1918 //	IsSameName
   1919 //===========================================================================================================================
   1920 
   1921 DEBUG_LOCAL BOOL
   1922 IsSameName( HostsFileInfo * node, const char * name )
   1923 {
   1924 	BOOL ret = TRUE;
   1925 
   1926 	check( node );
   1927 	check( name );
   1928 
   1929 	if ( strcmp( node->m_host.h_name, name ) != 0 )
   1930 	{
   1931 		int i;
   1932 
   1933 		for ( i = 0; node->m_host.h_aliases[i]; i++ )
   1934 		{
   1935 			if ( strcmp( node->m_host.h_aliases[i], name ) == 0 )
   1936 			{
   1937 				goto exit;
   1938 			}
   1939 		}
   1940 
   1941 		ret = FALSE;
   1942 	}
   1943 
   1944 exit:
   1945 
   1946 	return ret;
   1947 }
   1948 
   1949 
   1950 //===========================================================================================================================
   1951 //	HostsFileOpen
   1952 //===========================================================================================================================
   1953 
   1954 DEBUG_LOCAL OSStatus
   1955 HostsFileOpen( HostsFile ** self, const char * fname )
   1956 {
   1957 	OSStatus err = kNoErr;
   1958 
   1959 	*self = (HostsFile*) malloc( sizeof( HostsFile ) );
   1960 	require_action( *self, exit, err = kNoMemoryErr );
   1961 	memset( *self, 0, sizeof( HostsFile ) );
   1962 
   1963 	(*self)->m_bufferSize = BUFFER_INITIAL_SIZE;
   1964 	(*self)->m_buffer = (char*) malloc( (*self)->m_bufferSize );
   1965 	require_action( (*self)->m_buffer, exit, err = kNoMemoryErr );
   1966 
   1967 	// check malloc
   1968 
   1969 	(*self)->m_fp = fopen( fname, "r" );
   1970 	require_action( (*self)->m_fp, exit, err = kUnknownErr );
   1971 
   1972 exit:
   1973 
   1974 	if ( err && *self )
   1975 	{
   1976 		HostsFileClose( *self );
   1977 		*self = NULL;
   1978 	}
   1979 
   1980 	return err;
   1981 }
   1982 
   1983 
   1984 //===========================================================================================================================
   1985 //	HostsFileClose
   1986 //===========================================================================================================================
   1987 
   1988 DEBUG_LOCAL OSStatus
   1989 HostsFileClose( HostsFile * self )
   1990 {
   1991 	check( self );
   1992 
   1993 	if ( self->m_buffer )
   1994 	{
   1995 		free( self->m_buffer );
   1996 		self->m_buffer = NULL;
   1997 	}
   1998 
   1999 	if ( self->m_fp )
   2000 	{
   2001 		fclose( self->m_fp );
   2002 		self->m_fp = NULL;
   2003 	}
   2004 
   2005 	free( self );
   2006 
   2007 	return kNoErr;
   2008 }
   2009 
   2010 
   2011 //===========================================================================================================================
   2012 //	HostsFileInfoFree
   2013 //===========================================================================================================================
   2014 
   2015 DEBUG_LOCAL void
   2016 HostsFileInfoFree( HostsFileInfo * info )
   2017 {
   2018 	while ( info )
   2019 	{
   2020 		HostsFileInfo * next = info->m_next;
   2021 
   2022 		if ( info->m_host.h_addr_list )
   2023 		{
   2024 			if ( info->m_host.h_addr_list[0] )
   2025 			{
   2026 				free( info->m_host.h_addr_list[0] );
   2027 				info->m_host.h_addr_list[0] = NULL;
   2028 			}
   2029 
   2030 			free( info->m_host.h_addr_list );
   2031 			info->m_host.h_addr_list = NULL;
   2032 		}
   2033 
   2034 		if ( info->m_host.h_aliases )
   2035 		{
   2036 			int i;
   2037 
   2038 			for ( i = 0; info->m_host.h_aliases[i]; i++ )
   2039 			{
   2040 				free( info->m_host.h_aliases[i] );
   2041 			}
   2042 
   2043 			free( info->m_host.h_aliases );
   2044 		}
   2045 
   2046 		if ( info->m_host.h_name )
   2047 		{
   2048 			free( info->m_host.h_name );
   2049 			info->m_host.h_name = NULL;
   2050 		}
   2051 
   2052 		free( info );
   2053 
   2054 		info = next;
   2055 	}
   2056 }
   2057 
   2058 
   2059 //===========================================================================================================================
   2060 //	HostsFileNext
   2061 //===========================================================================================================================
   2062 
   2063 DEBUG_LOCAL OSStatus
   2064 HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo )
   2065 {
   2066 	struct sockaddr_in6	addr_6;
   2067 	struct sockaddr_in	addr_4;
   2068 	int					numAliases = ALIASES_INITIAL_SIZE;
   2069 	char			*	line;
   2070 	char			*	tok;
   2071 	int					dwSize;
   2072 	int					idx;
   2073 	int					i;
   2074 	short				family;
   2075 	OSStatus			err = kNoErr;
   2076 
   2077 	check( self );
   2078 	check( self->m_fp );
   2079 	check( hInfo );
   2080 
   2081 	idx	= 0;
   2082 
   2083 	*hInfo = (HostsFileInfo*) malloc( sizeof( HostsFileInfo ) );
   2084 	require_action( *hInfo, exit, err = kNoMemoryErr );
   2085 	memset( *hInfo, 0, sizeof( HostsFileInfo ) );
   2086 
   2087 	for ( ; ; )
   2088 	{
   2089 		line = fgets( self->m_buffer + idx, self->m_bufferSize - idx, self->m_fp );
   2090 
   2091 		if ( line == NULL )
   2092 		{
   2093 			err = 1;
   2094 			goto exit;
   2095 		}
   2096 
   2097 		// If there's no eol and no eof, then we didn't get the whole line
   2098 
   2099 		if ( !strchr( line, '\n' ) && !feof( self->m_fp ) )
   2100 		{
   2101 			int			bufferSize;
   2102 			char	*	buffer;
   2103 
   2104 			/* Try and allocate space for longer line */
   2105 
   2106 			bufferSize	= self->m_bufferSize * 2;
   2107 			buffer		= (char*) realloc( self->m_buffer, bufferSize );
   2108 			require_action( buffer, exit, err = kNoMemoryErr );
   2109 			self->m_bufferSize	= bufferSize;
   2110 			self->m_buffer		= buffer;
   2111 			idx					= (int) strlen( self->m_buffer );
   2112 
   2113 			continue;
   2114 		}
   2115 
   2116 		line	= self->m_buffer;
   2117 		idx		= 0;
   2118 
   2119 		if (*line == '#')
   2120 		{
   2121 			continue;
   2122 		}
   2123 
   2124 		// Get rid of either comments or eol characters
   2125 
   2126 		if (( tok = strpbrk(line, "#\n")) != NULL )
   2127 		{
   2128 			*tok = '\0';
   2129 		}
   2130 
   2131 		// Make sure there is some whitespace on this line
   2132 
   2133 		if (( tok = strpbrk(line, " \t")) == NULL )
   2134 		{
   2135 			continue;
   2136 		}
   2137 
   2138 		// Create two strings, where p == the IP Address and tok is the name list
   2139 
   2140 		*tok++ = '\0';
   2141 
   2142 		while ( *tok == ' ' || *tok == '\t')
   2143 		{
   2144 			tok++;
   2145 		}
   2146 
   2147 		// Now we have the name
   2148 
   2149 		(*hInfo)->m_host.h_name = (char*) malloc( strlen( tok ) + 1 );
   2150 		require_action( (*hInfo)->m_host.h_name, exit, err = kNoMemoryErr );
   2151 		strcpy( (*hInfo)->m_host.h_name, tok );
   2152 
   2153 		// Now create the address (IPv6/IPv4)
   2154 
   2155 		addr_6.sin6_family	= family = AF_INET6;
   2156 		dwSize				= sizeof( addr_6 );
   2157 
   2158 		if ( WSAStringToAddress( line, AF_INET6, NULL, ( struct sockaddr*) &addr_6, &dwSize ) != 0 )
   2159 		{
   2160 			addr_4.sin_family = family = AF_INET;
   2161 			dwSize = sizeof( addr_4 );
   2162 
   2163 			if (WSAStringToAddress( line, AF_INET, NULL, ( struct sockaddr*) &addr_4, &dwSize ) != 0 )
   2164 			{
   2165 				continue;
   2166 			}
   2167 		}
   2168 
   2169 		(*hInfo)->m_host.h_addr_list = (char**) malloc( sizeof( char**) * 2 );
   2170 		require_action( (*hInfo)->m_host.h_addr_list, exit, err = kNoMemoryErr );
   2171 
   2172 		if ( family == AF_INET6 )
   2173 		{
   2174 			(*hInfo)->m_host.h_length		= (short) sizeof( addr_6.sin6_addr );
   2175 			(*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
   2176 			require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
   2177 			memmove( (*hInfo)->m_host.h_addr_list[0], &addr_6.sin6_addr, sizeof( addr_6.sin6_addr ) );
   2178 
   2179 		}
   2180 		else
   2181 		{
   2182 			(*hInfo)->m_host.h_length		= (short) sizeof( addr_4.sin_addr );
   2183 			(*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
   2184 			require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
   2185 			memmove( (*hInfo)->m_host.h_addr_list[0], &addr_4.sin_addr, sizeof( addr_4.sin_addr ) );
   2186 		}
   2187 
   2188 		(*hInfo)->m_host.h_addr_list[1] = NULL;
   2189 		(*hInfo)->m_host.h_addrtype		= family;
   2190 
   2191 		// Now get the aliases
   2192 
   2193 		if ((tok = strpbrk(tok, " \t")) != NULL)
   2194 		{
   2195 			*tok++ = '\0';
   2196 		}
   2197 
   2198 		i = 0;
   2199 
   2200 		(*hInfo)->m_host.h_aliases		= (char**) malloc( sizeof(char**) * numAliases );
   2201 		require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
   2202 		(*hInfo)->m_host.h_aliases[0]	= NULL;
   2203 
   2204 		while ( tok && *tok )
   2205 		{
   2206 			// Skip over the whitespace, waiting for the start of the next alias name
   2207 
   2208 			if (*tok == ' ' || *tok == '\t')
   2209 			{
   2210 				tok++;
   2211 				continue;
   2212 			}
   2213 
   2214 			// Check to make sure we don't exhaust the alias buffer
   2215 
   2216 			if ( i >= ( numAliases - 1 ) )
   2217 			{
   2218 				numAliases = numAliases * 2;
   2219 				(*hInfo)->m_host.h_aliases = (char**) realloc( (*hInfo)->m_host.h_aliases, numAliases * sizeof( char** ) );
   2220 				require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
   2221 			}
   2222 
   2223 			(*hInfo)->m_host.h_aliases[i] = (char*) malloc( strlen( tok ) + 1 );
   2224 			require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr );
   2225 
   2226 			strcpy( (*hInfo)->m_host.h_aliases[i], tok );
   2227 
   2228 			if (( tok = strpbrk( tok, " \t")) != NULL )
   2229 			{
   2230 				*tok++ = '\0';
   2231 			}
   2232 
   2233 			(*hInfo)->m_host.h_aliases[++i] = NULL;
   2234 		}
   2235 
   2236 		break;
   2237 	}
   2238 
   2239 exit:
   2240 
   2241 	if ( err && ( *hInfo ) )
   2242 	{
   2243 		HostsFileInfoFree( *hInfo );
   2244 		*hInfo = NULL;
   2245 	}
   2246 
   2247 	return err;
   2248 }
   2249 
   2250 
   2251 #ifdef ENABLE_REVERSE_LOOKUP
   2252 //===========================================================================================================================
   2253 //	IsReverseLookup
   2254 //===========================================================================================================================
   2255 
   2256 DEBUG_LOCAL OSStatus
   2257 IsReverseLookup( LPCWSTR name, size_t size )
   2258 {
   2259 	LPCWSTR		p;
   2260 	OSStatus	err = kNoErr;
   2261 
   2262 	// IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa
   2263 	require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
   2264 
   2265 	p = name + ( size - 1 );
   2266 	p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
   2267 
   2268 	if	( ( ( p[ 0 ] != '.' )							||
   2269 		( ( p[ 1 ] != '0' ) )							||
   2270 		( ( p[ 2 ] != '.' ) )							||
   2271 		( ( p[ 3 ] != '8' ) )							||
   2272 		( ( p[ 4 ] != '.' ) )							||
   2273 		( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) )		||
   2274 		( ( p[ 6 ] != '.' ) )							||
   2275 		( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) )		||
   2276 		( ( p[ 8 ] != '.' ) )							||
   2277 		( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) )		||
   2278 		( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) )	||
   2279 		( ( p[ 11 ] != '6' ) )							||
   2280 		( ( p[ 12 ] != '.' ) )							||
   2281 		( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) )	||
   2282 		( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) )	||
   2283 		( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) )	||
   2284 		( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) )
   2285 	{
   2286 		require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
   2287 
   2288 		p = name + ( size - 1 );
   2289 		p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
   2290 
   2291 		require_action_quiet( ( ( p[ 0 ] == '.' )						 &&
   2292 								( ( p[ 1 ] == '2' ) )							&&
   2293 								( ( p[ 2 ] == '5' ) )							&&
   2294 								( ( p[ 3 ] == '4' ) )							&&
   2295 								( ( p[ 4 ] == '.' ) )							&&
   2296 								( ( p[ 5 ] == '1' ) )							&&
   2297 								( ( p[ 6 ] == '6' ) )							&&
   2298 								( ( p[ 7 ] == '9' ) )							&&
   2299 								( ( p[ 8 ] == '.' ) )							&&
   2300 								( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) )		&&
   2301 								( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) )	&&
   2302 								( ( p[ 11 ] == '-' ) )							&&
   2303 								( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) )	&&
   2304 								( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) )	&&
   2305 								( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) )	&&
   2306 								( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) )	&&
   2307 								( ( p[ 16 ] == '.' ) )							&&
   2308 								( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) )	&&
   2309 								( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) )	&&
   2310 								( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) )	&&
   2311 								( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ),
   2312 								exit, err = WSASERVICE_NOT_FOUND );
   2313 	}
   2314 
   2315 	// It's a reverse lookup
   2316 
   2317 	check( err == kNoErr );
   2318 
   2319 exit:
   2320 
   2321 	return err;
   2322 }
   2323 #endif
   2324 
   2325 //===========================================================================================================================
   2326 //	GetScopeId
   2327 //===========================================================================================================================
   2328 
   2329 DEBUG_LOCAL DWORD
   2330 GetScopeId( DWORD ifIndex )
   2331 {
   2332 	DWORD						err;
   2333 	int							i;
   2334 	DWORD						flags;
   2335 	struct ifaddrs *			head;
   2336 	struct ifaddrs **			next;
   2337 	IP_ADAPTER_ADDRESSES *		iaaList;
   2338 	ULONG						iaaListSize;
   2339 	IP_ADAPTER_ADDRESSES *		iaa;
   2340 	DWORD						scopeId = 0;
   2341 
   2342 	head	= NULL;
   2343 	next	= &head;
   2344 	iaaList	= NULL;
   2345 
   2346 	require( gGetAdaptersAddressesFunctionPtr, exit );
   2347 
   2348 	// Get the list of interfaces. The first call gets the size and the second call gets the actual data.
   2349 	// This loops to handle the case where the interface changes in the window after getting the size, but before the
   2350 	// second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
   2351 
   2352 	flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
   2353 	i = 0;
   2354 	for( ;; )
   2355 	{
   2356 		iaaListSize = 0;
   2357 		err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
   2358 		check( err == ERROR_BUFFER_OVERFLOW );
   2359 		check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
   2360 
   2361 		iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
   2362 		require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
   2363 
   2364 		err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
   2365 		if( err == ERROR_SUCCESS ) break;
   2366 
   2367 		free( iaaList );
   2368 		iaaList = NULL;
   2369 		++i;
   2370 		require( i < 100, exit );
   2371 		dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
   2372 	}
   2373 
   2374 	for( iaa = iaaList; iaa; iaa = iaa->Next )
   2375 	{
   2376 		DWORD ipv6IfIndex;
   2377 
   2378 		if ( iaa->IfIndex > 0xFFFFFF )
   2379 		{
   2380 			continue;
   2381 		}
   2382 		if ( iaa->Ipv6IfIndex > 0xFF )
   2383 		{
   2384 			continue;
   2385 		}
   2386 
   2387 		// For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
   2388 		// following code to crash when iterating through the prefix list.  This seems
   2389 		// to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
   2390 		// This shouldn't happen according to Microsoft docs which states:
   2391 		//
   2392 		//     "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
   2393 		//
   2394 		// So the data structure seems to be corrupted when we return from
   2395 		// GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
   2396 		// sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
   2397 		// modify iaa to have the correct values.
   2398 
   2399 		if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
   2400 		{
   2401 			ipv6IfIndex = iaa->Ipv6IfIndex;
   2402 		}
   2403 		else
   2404 		{
   2405 			ipv6IfIndex	= 0;
   2406 		}
   2407 
   2408 		// Skip psuedo and tunnel interfaces.
   2409 
   2410 		if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
   2411 		{
   2412 			continue;
   2413 		}
   2414 
   2415 		if ( iaa->IfIndex == ifIndex )
   2416 		{
   2417 			scopeId = iaa->Ipv6IfIndex;
   2418 			break;
   2419 		}
   2420 	}
   2421 
   2422 exit:
   2423 
   2424 	if( iaaList )
   2425 	{
   2426 		free( iaaList );
   2427 	}
   2428 
   2429 	return scopeId;
   2430 }
   2431