1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include "ClientCommon.h"
24 #include "CommonServices.h"
25 #include "DebugServices.h"
36 #pragma comment(lib, "DelayImp.lib")
39 #define swprintf _snwprintf
40 #define snprintf _snprintf
43 #define MAX_LABELS 128
46 #pragma mark == Structures ==
49 //===========================================================================================================================
51 //===========================================================================================================================
53 typedef struct Query
* QueryRef
;
54 typedef struct Query Query
;
60 WSAQUERYSETW
* querySet
;
65 HANDLE waitHandles
[ 3 ];
67 DNSServiceRef resolver4
;
68 DNSServiceRef resolver6
;
69 char name
[ kDNSServiceMaxDomainName
];
71 uint8_t numValidAddrs
;
79 #define BUFFER_INITIAL_SIZE 4192
80 #define ALIASES_INITIAL_SIZE 5
82 typedef struct HostsFile
90 typedef struct HostsFileInfo
92 struct hostent m_host
;
93 struct HostsFileInfo
* m_next
;
98 #pragma mark == Prototypes ==
101 //===========================================================================================================================
103 //===========================================================================================================================
107 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
108 STDAPI
DllRegisterServer( void );
109 STDAPI
DllRegisterServer( void );
114 int WSPAPI
NSPCleanup( LPGUID inProviderID
);
116 DEBUG_LOCAL
int WSPAPI
117 NSPLookupServiceBegin(
119 LPWSAQUERYSETW inQuerySet
,
120 LPWSASERVICECLASSINFOW inServiceClassInfo
,
122 LPHANDLE outLookup
);
124 DEBUG_LOCAL
int WSPAPI
125 NSPLookupServiceNext(
128 LPDWORD ioBufferLength
,
129 LPWSAQUERYSETW outResults
);
131 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
);
133 DEBUG_LOCAL
int WSPAPI
136 LPWSASERVICECLASSINFOW inServiceClassInfo
,
137 LPWSAQUERYSETW inRegInfo
,
138 WSAESETSERVICEOP inOperation
,
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
);
147 #define NSPLock() EnterCriticalSection( &gLock );
148 #define NSPUnlock() LeaveCriticalSection( &gLock );
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
);
154 DEBUG_LOCAL
void CALLBACK_COMPAT
155 QueryRecordCallback4(
157 DNSServiceFlags inFlags
,
158 uint32_t inInterfaceIndex
,
159 DNSServiceErrorType inErrorCode
,
163 uint16_t inRDataSize
,
164 const void * inRData
,
168 DEBUG_LOCAL
void CALLBACK_COMPAT
169 QueryRecordCallback6(
171 DNSServiceFlags inFlags
,
172 uint32_t inInterfaceIndex
,
173 DNSServiceErrorType inErrorCode
,
177 uint16_t inRDataSize
,
178 const void * inRData
,
185 const WSAQUERYSETW
* inQuerySet
,
186 DWORD inQuerySetFlags
,
187 WSAQUERYSETW
** outQuerySet
,
193 const WSAQUERYSETW
* inQuerySet
,
194 DWORD inQuerySetFlags
,
195 WSAQUERYSETW
* outQuerySet
);
197 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
);
200 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
);
202 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
204 #define dlog_query_set( LEVEL, SET )
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
);
216 #ifdef ENABLE_REVERSE_LOOKUP
217 DEBUG_LOCAL OSStatus
IsReverseLookup( LPCWSTR name
, size_t size
);
222 #pragma mark == Globals ==
225 //===========================================================================================================================
227 //===========================================================================================================================
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
;
239 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
243 PIP_ADAPTER_ADDRESSES inAdapter
,
244 PULONG outBufferSize
);
246 DEBUG_LOCAL HMODULE gIPHelperLibraryInstance
= NULL
;
247 DEBUG_LOCAL GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
255 //===========================================================================================================================
257 //===========================================================================================================================
259 BOOL APIENTRY
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
)
261 DEBUG_USE_ONLY( inInstance
);
262 DEBUG_UNUSED( inReserved
);
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__
);
276 case DLL_PROCESS_DETACH
:
277 HostsFileInfoFree( gHostsFileInfo
);
278 gHostsFileInfo
= NULL
;
279 dlog( kDebugLevelVerbose
, "%s: process detach\n", __ROUTINE__
);
282 case DLL_THREAD_ATTACH
:
283 dlog( kDebugLevelVerbose
, "%s: thread attach\n", __ROUTINE__
);
286 case DLL_THREAD_DETACH
:
287 dlog( kDebugLevelVerbose
, "%s: thread detach\n", __ROUTINE__
);
291 dlog( kDebugLevelNotice
, "%s: unknown reason code (%d)\n", __ROUTINE__
, inReason
);
299 //===========================================================================================================================
301 //===========================================================================================================================
303 STDAPI
DllRegisterServer( void )
306 WCHAR path
[ MAX_PATH
];
309 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
311 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
312 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
313 require_noerr( err
, exit
);
315 // Unregister before registering to workaround an installer
316 // problem during upgrade installs.
318 WSCUnInstallNameSpace( &gNSPGUID
);
320 err
= GetModuleFileNameW( gInstance
, path
, MAX_PATH
);
321 err
= translate_errno( err
!= 0, errno_compat(), kUnknownErr
);
322 require_noerr( err
, exit
);
324 err
= WSCInstallNameSpace( gNSPName
, path
, NS_DNS
, 1, &gNSPGUID
);
325 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
326 require_noerr( err
, exit
);
334 //===========================================================================================================================
335 // DllUnregisterServer
336 //===========================================================================================================================
338 STDAPI
DllUnregisterServer( void )
343 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
345 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
346 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
347 require_noerr( err
, exit
);
349 err
= WSCUnInstallNameSpace( &gNSPGUID
);
350 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
351 require_noerr( err
, exit
);
360 //===========================================================================================================================
363 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
364 //===========================================================================================================================
366 int WSPAPI
NSPStartup( LPGUID inProviderID
, LPNSP_ROUTINE outRoutines
)
370 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
371 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
373 // Only initialize if this is the first time NSPStartup is called.
375 if( InterlockedIncrement( &gRefCount
) != 1 )
381 // Initialize our internal state.
383 InitializeCriticalSection( &gLock
);
384 gLockInitialized
= true;
386 // Set the size to exclude NSPIoctl because we don't implement it.
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
;
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
403 if ( !gIPHelperLibraryInstance
)
405 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
406 if( gIPHelperLibraryInstance
)
408 gGetAdaptersAddressesFunctionPtr
= (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
415 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
416 if( err
!= NO_ERROR
)
418 NSPCleanup( inProviderID
);
419 SetLastError( (DWORD
) err
);
420 return( SOCKET_ERROR
);
425 //===========================================================================================================================
428 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
429 //===========================================================================================================================
431 int WSPAPI
NSPCleanup( LPGUID inProviderID
)
433 DEBUG_USE_ONLY( inProviderID
);
435 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
436 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
438 // Only initialize if this is the first time NSPStartup is called.
440 if( InterlockedDecrement( &gRefCount
) != 0 )
445 // Stop any outstanding queries.
447 if( gLockInitialized
)
453 check_string( gQueryList
->refCount
== 1, "NSPCleanup with outstanding queries!" );
454 QueryRelease( gQueryList
);
456 if( gLockInitialized
)
461 if( gLockInitialized
)
463 gLockInitialized
= false;
464 DeleteCriticalSection( &gLock
);
467 if( gIPHelperLibraryInstance
)
471 ok
= FreeLibrary( gIPHelperLibraryInstance
);
472 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
473 gIPHelperLibraryInstance
= NULL
;
477 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
481 //===========================================================================================================================
482 // NSPLookupServiceBegin
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 //===========================================================================================================================
489 DEBUG_LOCAL
int WSPAPI
490 NSPLookupServiceBegin(
492 LPWSAQUERYSETW inQuerySet
,
493 LPWSASERVICECLASSINFOW inServiceClassInfo
,
508 DEBUG_UNUSED( inProviderID
);
509 DEBUG_UNUSED( inServiceClassInfo
);
511 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
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
);
519 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__
, inFlags
, name
);
520 dlog_query_set( kDebugLevelVerbose
, inQuerySet
);
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.
525 require_action_quiet( inFlags
& (LUP_RETURN_ADDR
|LUP_RETURN_BLOB
), exit
, err
= WSASERVICE_NOT_FOUND
);
527 type
= inQuerySet
->dwNameSpace
;
528 require_action_quiet( ( type
== NS_DNS
) || ( type
== NS_ALL
), exit
, err
= WSASERVICE_NOT_FOUND
);
530 n
= inQuerySet
->dwNumberOfProtocols
;
533 require_action( inQuerySet
->lpafpProtocols
, exit
, err
= WSAEINVAL
);
534 for( i
= 0; i
< n
; ++i
)
536 family
= inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
;
537 protocol
= inQuerySet
->lpafpProtocols
[ i
].iProtocol
;
538 if( ( family
== AF_INET
) && ( ( protocol
== IPPROTO_UDP
) || ( protocol
== IPPROTO_TCP
) ) )
543 require_action_quiet( i
< n
, exit
, err
= WSASERVICE_NOT_FOUND
);
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.
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
);
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' ) ) ) )
565 #ifdef ENABLE_REVERSE_LOOKUP
567 err
= IsReverseLookup( name
, size
);
571 err
= WSASERVICE_NOT_FOUND
;
575 require_noerr( err
, exit
);
579 const char * replyDomain
;
580 char translated
[ kDNSServiceMaxDomainName
];
583 const char * label
[MAX_LABELS
];
586 n
= WideCharToMultiByte( CP_UTF8
, 0, name
, -1, translated
, sizeof( translated
), NULL
, NULL
);
587 require_action( n
> 0, exit
, err
= WSASERVICE_NOT_FOUND
);
589 // <rdar://problem/4050633>
591 // Don't resolve multi-label name
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
;
598 while (replyDomain
&& *replyDomain
&& labels
< MAX_LABELS
)
600 label
[labels
++] = replyDomain
;
601 replyDomain
= GetNextLabel(replyDomain
, text
);
604 require_action( labels
== 2, exit
, err
= WSASERVICE_NOT_FOUND
);
606 // <rdar://problem/3936771>
608 // Check to see if the name of this host is in the hosts table. If so,
609 // don't try and resolve it
611 require_action( InHostsTable( translated
) == FALSE
, exit
, err
= WSASERVICE_NOT_FOUND
);
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.
618 err
= QueryCreate( inQuerySet
, inFlags
, &obj
);
620 require_noerr( err
, exit
);
622 *outLookup
= (HANDLE
) obj
;
625 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
626 if( err
!= NO_ERROR
)
628 SetLastError( (DWORD
) err
);
629 return( SOCKET_ERROR
);
634 //===========================================================================================================================
635 // NSPLookupServiceNext
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 //===========================================================================================================================
642 DEBUG_LOCAL
int WSPAPI
643 NSPLookupServiceNext(
647 LPWSAQUERYSETW outResults
)
656 DEBUG_USE_ONLY( inFlags
);
658 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
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
);
670 dlog( kDebugLevelTrace
, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__
, inLookup
, inFlags
, *ioSize
);
672 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
675 waitResult
= WaitForMultipleObjects( obj
->waitCount
, obj
->waitHandles
, FALSE
, 2 * 1000 );
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
);
681 // If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
683 if ( waitResult
== WAIT_OBJECT_0
+ 1 )
686 data6
= WaitForSingleObject( obj
->data6Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
689 // Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
691 else if ( waitResult
== WAIT_OBJECT_0
+ 2 )
693 data4
= WaitForSingleObject( obj
->data4Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
701 err
= DNSServiceProcessResult(obj
->resolver4
);
703 __except( EXCEPTION_EXECUTE_HANDLER
)
708 require_noerr( err
, exit
);
715 err
= DNSServiceProcessResult( obj
->resolver6
);
717 __except( EXCEPTION_EXECUTE_HANDLER
)
722 require_noerr( err
, exit
);
725 require_action_quiet( obj
->addr4Valid
|| obj
->addr6Valid
, exit
, err
= WSA_E_NO_MORE
);
727 // Copy the externalized query results to the callers buffer (if it fits).
729 size
= QueryCopyQuerySetSize( obj
, obj
->querySet
, obj
->querySetFlags
);
730 require_action( size
<= (size_t) *ioSize
, exit
, err
= WSAEFAULT
);
732 QueryCopyQuerySetTo( obj
, obj
->querySet
, obj
->querySetFlags
, outResults
);
733 outResults
->dwOutputFlags
= RESULT_IS_ADDED
;
734 obj
->addr4Valid
= false;
735 obj
->addr6Valid
= false;
743 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
744 if( err
!= NO_ERROR
)
746 SetLastError( (DWORD
) err
);
747 return( SOCKET_ERROR
);
752 //===========================================================================================================================
753 // NSPLookupServiceEnd
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 //===========================================================================================================================
760 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
)
764 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
766 dlog( kDebugLevelTrace
, "%s (lookup=%#p)\n", __ROUTINE__
, inLookup
);
769 err
= QueryRelease( (QueryRef
) inLookup
);
771 require_noerr( err
, exit
);
774 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
775 if( err
!= NO_ERROR
)
777 SetLastError( (DWORD
) err
);
778 return( SOCKET_ERROR
);
783 //===========================================================================================================================
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 //===========================================================================================================================
792 DEBUG_LOCAL
int WSPAPI
795 LPWSASERVICECLASSINFOW inServiceClassInfo
,
796 LPWSAQUERYSETW inRegInfo
,
797 WSAESETSERVICEOP inOperation
,
800 DEBUG_UNUSED( inProviderID
);
801 DEBUG_UNUSED( inServiceClassInfo
);
802 DEBUG_UNUSED( inRegInfo
);
803 DEBUG_UNUSED( inOperation
);
804 DEBUG_UNUSED( inFlags
);
806 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
807 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
809 // We don't allow services to be registered so always return an error.
811 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
815 //===========================================================================================================================
816 // NSPInstallServiceClass
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 //===========================================================================================================================
823 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
)
825 DEBUG_UNUSED( inProviderID
);
826 DEBUG_UNUSED( inServiceClassInfo
);
828 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
829 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
831 // We don't allow service classes to be installed so always return an error.
833 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
834 return( WSA_INVALID_PARAMETER
);
837 //===========================================================================================================================
838 // NSPRemoveServiceClass
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
843 //===========================================================================================================================
845 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
)
847 DEBUG_UNUSED( inProviderID
);
848 DEBUG_UNUSED( inServiceClassID
);
850 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
851 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
853 // We don't allow service classes to be installed so always return an error.
855 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
856 return( WSATYPE_NOT_FOUND
);
859 //===========================================================================================================================
860 // NSPGetServiceClassInfo
862 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
863 // a given service class.
864 //===========================================================================================================================
866 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
)
868 DEBUG_UNUSED( inProviderID
);
869 DEBUG_UNUSED( ioSize
);
870 DEBUG_UNUSED( ioServiceClassInfo
);
872 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
873 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
875 // We don't allow service classes to be installed so always return an error.
877 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
878 return( WSATYPE_NOT_FOUND
);
885 //===========================================================================================================================
888 // Warning: Assumes the NSP lock is held.
889 //===========================================================================================================================
891 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
)
895 char name
[ kDNSServiceMaxDomainName
];
903 check( inQuerySet
->lpszServiceInstanceName
);
906 // Convert the wchar_t name to UTF-8.
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
);
912 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
914 obj
= (QueryRef
) calloc( 1, sizeof( *obj
) );
915 require_action( obj
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
919 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
) {} // Find the end of the list.
922 // Set up cancel event
924 obj
->cancelEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
925 require_action( obj
->cancelEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
927 // Set up events to signal when A record data is ready
929 obj
->data4Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
930 require_action( obj
->data4Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
932 // Start the query. Handle delay loaded DLL errors.
936 err
= DNSServiceQueryRecord( &obj
->resolver4
, 0, 0, name
, kDNSServiceType_A
, kDNSServiceClass_IN
, QueryRecordCallback4
, obj
);
938 __except( EXCEPTION_EXECUTE_HANDLER
)
943 require_noerr( err
, exit
);
945 // Attach the socket to the event
949 s4
= DNSServiceRefSockFD(obj
->resolver4
);
951 __except( EXCEPTION_EXECUTE_HANDLER
)
956 err
= translate_errno( s4
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
957 require_noerr( err
, exit
);
959 WSAEventSelect(s4
, obj
->data4Event
, FD_READ
|FD_CLOSE
);
961 // Set up events to signal when AAAA record data is ready
963 obj
->data6Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
964 require_action( obj
->data6Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
966 // Start the query. Handle delay loaded DLL errors.
970 err
= DNSServiceQueryRecord( &obj
->resolver6
, 0, 0, name
, kDNSServiceType_AAAA
, kDNSServiceClass_IN
, QueryRecordCallback6
, obj
);
972 __except( EXCEPTION_EXECUTE_HANDLER
)
977 require_noerr( err
, exit
);
979 // Attach the socket to the event
983 s6
= DNSServiceRefSockFD(obj
->resolver6
);
985 __except( EXCEPTION_EXECUTE_HANDLER
)
990 err
= translate_errno( s6
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
991 require_noerr( err
, exit
);
993 WSAEventSelect(s6
, obj
->data6Event
, FD_READ
|FD_CLOSE
);
996 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->cancelEvent
;
997 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data4Event
;
998 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data6Event
;
1000 check( obj
->waitCount
== sizeof_array( obj
->waitHandles
) );
1002 // Copy the QuerySet so it can be returned later.
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
);
1018 QueryRelease( obj
);
1023 //===========================================================================================================================
1026 // Warning: Assumes the NSP lock is held.
1027 //===========================================================================================================================
1029 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
)
1034 for( obj
= gQueryList
; obj
; obj
= obj
->next
)
1041 require_action( obj
, exit
, err
= WSA_INVALID_HANDLE
);
1050 //===========================================================================================================================
1053 // Warning: Assumes the NSP lock is held.
1054 //===========================================================================================================================
1056 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
)
1062 // Find the item in the list.
1064 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
)
1071 require_action( *p
, exit
, err
= WSA_INVALID_HANDLE
);
1073 // Signal a cancel to unblock any threads waiting for results.
1075 if( inRef
->cancelEvent
)
1077 ok
= SetEvent( inRef
->cancelEvent
);
1078 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1083 if( inRef
->resolver4
)
1087 DNSServiceRefDeallocate( inRef
->resolver4
);
1089 __except( EXCEPTION_EXECUTE_HANDLER
)
1093 inRef
->resolver4
= NULL
;
1096 if ( inRef
->resolver6
)
1100 DNSServiceRefDeallocate( inRef
->resolver6
);
1102 __except( EXCEPTION_EXECUTE_HANDLER
)
1106 inRef
->resolver6
= NULL
;
1109 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
1111 if( --inRef
->refCount
!= 0 )
1118 // Release resources.
1120 if( inRef
->cancelEvent
)
1122 ok
= CloseHandle( inRef
->cancelEvent
);
1123 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1125 if( inRef
->data4Event
)
1127 ok
= CloseHandle( inRef
->data4Event
);
1128 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1130 if( inRef
->data6Event
)
1132 ok
= CloseHandle( inRef
->data6Event
);
1133 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1135 if( inRef
->querySet
)
1137 free( inRef
->querySet
);
1146 //===========================================================================================================================
1147 // QueryRecordCallback4
1148 //===========================================================================================================================
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
,
1159 uint16_t inRDataSize
,
1160 const void * inRData
,
1169 DEBUG_UNUSED( inFlags
);
1170 DEBUG_UNUSED( inInterfaceIndex
);
1171 DEBUG_UNUSED( inTTL
);
1174 obj
= (QueryRef
) inContext
;
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
);
1182 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1183 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1185 // Copy the name if needed.
1187 if( obj
->name
[ 0 ] == '\0' )
1191 while( *src
!= '\0' )
1196 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1197 check( obj
->nameSize
< sizeof( obj
->name
) );
1202 memcpy( &obj
->addr4
, inRData
, inRDataSize
);
1203 obj
->addr4Valid
= true;
1204 obj
->numValidAddrs
++;
1206 // Signal that a result is ready.
1208 check( obj
->data4Event
);
1209 ok
= SetEvent( obj
->data4Event
);
1210 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1212 // Stop the resolver after the first response.
1216 DNSServiceRefDeallocate( inRef
);
1218 __except( EXCEPTION_EXECUTE_HANDLER
)
1222 obj
->resolver4
= NULL
;
1233 //===========================================================================================================================
1234 // QueryRecordCallback6
1235 //===========================================================================================================================
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
,
1246 uint16_t inRDataSize
,
1247 const void * inRData
,
1256 DEBUG_UNUSED( inFlags
);
1257 DEBUG_UNUSED( inInterfaceIndex
);
1258 DEBUG_UNUSED( inTTL
);
1261 obj
= (QueryRef
) inContext
;
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
);
1269 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1270 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1272 // Copy the name if needed.
1274 if( obj
->name
[ 0 ] == '\0' )
1278 while( *src
!= '\0' )
1283 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1284 check( obj
->nameSize
< sizeof( obj
->name
) );
1289 memcpy( &obj
->addr6
, inRData
, inRDataSize
);
1291 obj
->addr6ScopeId
= GetScopeId( inInterfaceIndex
);
1292 require( obj
->addr6ScopeId
, exit
);
1293 obj
->addr6Valid
= true;
1294 obj
->numValidAddrs
++;
1296 // Signal that we're done
1298 check( obj
->data6Event
);
1299 ok
= SetEvent( obj
->data6Event
);
1300 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1302 // Stop the resolver after the first response.
1306 DNSServiceRefDeallocate( inRef
);
1308 __except( EXCEPTION_EXECUTE_HANDLER
)
1312 obj
->resolver6
= NULL
;
1322 //===========================================================================================================================
1323 // QueryCopyQuerySet
1325 // Warning: Assumes the NSP lock is held.
1326 //===========================================================================================================================
1328 DEBUG_LOCAL OSStatus
1331 const WSAQUERYSETW
* inQuerySet
,
1332 DWORD inQuerySetFlags
,
1333 WSAQUERYSETW
** outQuerySet
,
1340 check( inQuerySet
);
1341 check( outQuerySet
);
1343 size
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1344 qs
= (WSAQUERYSETW
*) calloc( 1, size
);
1345 require_action( qs
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1347 QueryCopyQuerySetTo( inRef
, inQuerySet
, inQuerySetFlags
, qs
);
1367 //===========================================================================================================================
1368 // QueryCopyQuerySetTo
1370 // Warning: Assumes the NSP lock is held.
1371 //===========================================================================================================================
1374 QueryCopyQuerySetTo(
1376 const WSAQUERYSETW
* inQuerySet
,
1377 DWORD inQuerySetFlags
,
1378 WSAQUERYSETW
* outQuerySet
)
1389 debugSize
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1392 check( inQuerySet
);
1393 check( outQuerySet
);
1395 dst
= (uint8_t *) outQuerySet
;
1397 // Copy the static portion of the results.
1399 *outQuerySet
= *inQuerySet
;
1400 dst
+= sizeof( *inQuerySet
);
1402 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1404 s
= inQuerySet
->lpszServiceInstanceName
;
1407 outQuerySet
->lpszServiceInstanceName
= (LPWSTR
) dst
;
1409 while( ( *q
++ = *s
++ ) != 0 ) {}
1410 dst
= (uint8_t *) q
;
1415 outQuerySet
->lpszServiceInstanceName
= NULL
;
1418 if( inQuerySet
->lpServiceClassId
)
1420 outQuerySet
->lpServiceClassId
= (LPGUID
) dst
;
1421 *outQuerySet
->lpServiceClassId
= *inQuerySet
->lpServiceClassId
;
1422 dst
+= sizeof( *inQuerySet
->lpServiceClassId
);
1425 if( inQuerySet
->lpVersion
)
1427 outQuerySet
->lpVersion
= (LPWSAVERSION
) dst
;
1428 *outQuerySet
->lpVersion
= *inQuerySet
->lpVersion
;
1429 dst
+= sizeof( *inQuerySet
->lpVersion
);
1432 s
= inQuerySet
->lpszComment
;
1435 outQuerySet
->lpszComment
= (LPWSTR
) dst
;
1437 while( ( *q
++ = *s
++ ) != 0 ) {}
1438 dst
= (uint8_t *) q
;
1441 if( inQuerySet
->lpNSProviderId
)
1443 outQuerySet
->lpNSProviderId
= (LPGUID
) dst
;
1444 *outQuerySet
->lpNSProviderId
= *inQuerySet
->lpNSProviderId
;
1445 dst
+= sizeof( *inQuerySet
->lpNSProviderId
);
1448 s
= inQuerySet
->lpszContext
;
1451 outQuerySet
->lpszContext
= (LPWSTR
) dst
;
1453 while( ( *q
++ = *s
++ ) != 0 ) {}
1454 dst
= (uint8_t *) q
;
1457 n
= inQuerySet
->dwNumberOfProtocols
;
1461 check( inQuerySet
->lpafpProtocols
);
1463 outQuerySet
->lpafpProtocols
= (LPAFPROTOCOLS
) dst
;
1464 for( i
= 0; i
< n
; ++i
)
1466 outQuerySet
->lpafpProtocols
[ i
] = inQuerySet
->lpafpProtocols
[ i
];
1467 dst
+= sizeof( *inQuerySet
->lpafpProtocols
);
1471 s
= inQuerySet
->lpszQueryString
;
1474 outQuerySet
->lpszQueryString
= (LPWSTR
) dst
;
1476 while( ( *q
++ = *s
++ ) != 0 ) {}
1477 dst
= (uint8_t *) q
;
1480 // Copy the address(es).
1482 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && ( inRef
->numValidAddrs
> 0 ) )
1484 struct sockaddr_in
* addr4
;
1485 struct sockaddr_in6
* addr6
;
1488 outQuerySet
->dwNumberOfCsAddrs
= inRef
->numValidAddrs
;
1489 outQuerySet
->lpcsaBuffer
= (LPCSADDR_INFO
) dst
;
1490 dst
+= ( sizeof( *outQuerySet
->lpcsaBuffer
) ) * ( inRef
->numValidAddrs
) ;
1493 if ( inRef
->addr4Valid
)
1495 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1496 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1498 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1499 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in
);
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
);
1507 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET
; // Emulate Tcpip NSP
1508 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1513 if ( inRef
->addr6Valid
)
1515 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1516 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1518 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1519 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in6
);
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
);
1528 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET6
; // Emulate Tcpip NSP
1529 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1534 outQuerySet
->dwNumberOfCsAddrs
= 0;
1535 outQuerySet
->lpcsaBuffer
= NULL
;
1538 // Copy the hostent blob.
1540 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1543 struct hostent
* he
;
1546 outQuerySet
->lpBlob
= (LPBLOB
) dst
;
1547 dst
+= sizeof( *outQuerySet
->lpBlob
);
1550 he
= (struct hostent
*) dst
;
1551 dst
+= sizeof( *he
);
1553 he
->h_name
= (char *)( dst
- base
);
1554 memcpy( dst
, inRef
->name
, inRef
->nameSize
+ 1 );
1555 dst
+= ( inRef
->nameSize
+ 1 );
1557 he
->h_aliases
= (char **)( dst
- base
);
1558 p
= (uintptr_t *) dst
;
1560 dst
= (uint8_t *) p
;
1562 he
->h_addrtype
= AF_INET
;
1565 he
->h_addr_list
= (char **)( dst
- base
);
1566 p
= (uintptr_t *) dst
;
1567 dst
+= ( 2 * sizeof( *p
) );
1568 *p
++ = (uintptr_t)( dst
- base
);
1570 p
= (uintptr_t *) dst
;
1571 *p
++ = (uintptr_t) inRef
->addr4
;
1572 dst
= (uint8_t *) p
;
1574 outQuerySet
->lpBlob
->cbSize
= (ULONG
)( dst
- base
);
1575 outQuerySet
->lpBlob
->pBlobData
= (BYTE
*) base
;
1577 dlog_query_set( kDebugLevelVerbose
, outQuerySet
);
1579 check( (size_t)( dst
- ( (uint8_t *) outQuerySet
) ) == debugSize
);
1582 //===========================================================================================================================
1583 // QueryCopyQuerySetSize
1585 // Warning: Assumes the NSP lock is held.
1586 //===========================================================================================================================
1588 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
)
1595 check( inQuerySet
);
1597 // Calculate the size of the static portion of the results.
1599 size
= sizeof( *inQuerySet
);
1601 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1603 s
= inQuerySet
->lpszServiceInstanceName
;
1606 for( p
= s
; *p
; ++p
) {}
1607 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1611 if( inQuerySet
->lpServiceClassId
)
1613 size
+= sizeof( *inQuerySet
->lpServiceClassId
);
1616 if( inQuerySet
->lpVersion
)
1618 size
+= sizeof( *inQuerySet
->lpVersion
);
1621 s
= inQuerySet
->lpszComment
;
1624 for( p
= s
; *p
; ++p
) {}
1625 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1628 if( inQuerySet
->lpNSProviderId
)
1630 size
+= sizeof( *inQuerySet
->lpNSProviderId
);
1633 s
= inQuerySet
->lpszContext
;
1636 for( p
= s
; *p
; ++p
) {}
1637 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1640 size
+= ( inQuerySet
->dwNumberOfProtocols
* sizeof( *inQuerySet
->lpafpProtocols
) );
1642 s
= inQuerySet
->lpszQueryString
;
1645 for( p
= s
; *p
; ++p
) {}
1646 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1649 // Calculate the size of the address(es).
1651 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr4Valid
)
1653 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1654 size
+= sizeof( struct sockaddr_in
);
1657 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr6Valid
)
1659 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1660 size
+= sizeof( struct sockaddr_in6
);
1663 // Calculate the size of the hostent blob.
1665 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
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
1683 //===========================================================================================================================
1684 // DebugDumpQuerySet
1685 //===========================================================================================================================
1687 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1688 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1690 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1691 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1693 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1695 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
)
1699 check( inQuerySet
);
1701 // Fixed portion of the QuerySet.
1703 dlog( inLevel
, "QuerySet:\n" );
1704 dlog( inLevel
, " dwSize: %d (expected %d)\n", inQuerySet
->dwSize
, sizeof( *inQuerySet
) );
1705 if( inQuerySet
->lpszServiceInstanceName
)
1707 dlog( inLevel
, " lpszServiceInstanceName: %S\n", inQuerySet
->lpszServiceInstanceName
);
1711 dlog( inLevel
, " lpszServiceInstanceName: <null>\n" );
1713 if( inQuerySet
->lpServiceClassId
)
1715 dlog( inLevel
, " lpServiceClassId: %U\n", inQuerySet
->lpServiceClassId
);
1719 dlog( inLevel
, " lpServiceClassId: <null>\n" );
1721 if( inQuerySet
->lpVersion
)
1723 dlog( inLevel
, " lpVersion:\n" );
1724 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->dwVersion
);
1725 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->ecHow
);
1729 dlog( inLevel
, " lpVersion: <null>\n" );
1731 if( inQuerySet
->lpszComment
)
1733 dlog( inLevel
, " lpszComment: %S\n", inQuerySet
->lpszComment
);
1737 dlog( inLevel
, " lpszComment: <null>\n" );
1739 dlog( inLevel
, " dwNameSpace: %d %s\n", inQuerySet
->dwNameSpace
,
1740 DebugNameSpaceToString( inQuerySet
->dwNameSpace
) );
1741 if( inQuerySet
->lpNSProviderId
)
1743 dlog( inLevel
, " lpNSProviderId: %U\n", inQuerySet
->lpNSProviderId
);
1747 dlog( inLevel
, " lpNSProviderId: <null>\n" );
1749 if( inQuerySet
->lpszContext
)
1751 dlog( inLevel
, " lpszContext: %S\n", inQuerySet
->lpszContext
);
1755 dlog( inLevel
, " lpszContext: <null>\n" );
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
)
1763 dlog( inLevel
, "\n" );
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
) );
1770 if( inQuerySet
->lpszQueryString
)
1772 dlog( inLevel
, " lpszQueryString: %S\n", inQuerySet
->lpszQueryString
);
1776 dlog( inLevel
, " lpszQueryString: <null>\n" );
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
)
1784 dlog( inLevel
, "\n" );
1786 if( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
&&
1787 ( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.iSockaddrLength
> 0 ) )
1789 dlog( inLevel
, " LocalAddr: %##a\n",
1790 inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
);
1794 dlog( inLevel
, " LocalAddr: <null/empty>\n" );
1796 if( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
&&
1797 ( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.iSockaddrLength
> 0 ) )
1799 dlog( inLevel
, " RemoteAddr: %##a\n",
1800 inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
);
1804 dlog( inLevel
, " RemoteAddr: <null/empty>\n" );
1806 dlog( inLevel
, " iSocketType: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iSocketType
);
1807 dlog( inLevel
, " iProtocol: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iProtocol
);
1809 dlog( inLevel
, " dwOutputFlags: %d\n", inQuerySet
->dwOutputFlags
);
1811 // Blob portion of the QuerySet.
1813 if( inQuerySet
->lpBlob
)
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 );
1824 dlog( inLevel
, " lpBlob: <null>\n" );
1830 //===========================================================================================================================
1832 //===========================================================================================================================
1835 InHostsTable( const char * name
)
1837 HostsFileInfo
* node
;
1843 if ( gHostsFileInfo
== NULL
)
1845 TCHAR systemDirectory
[MAX_PATH
];
1846 TCHAR hFileName
[MAX_PATH
];
1849 GetSystemDirectory( systemDirectory
, sizeof( systemDirectory
) );
1850 snprintf( hFileName
, sizeof( hFileName
), "%s\\drivers\\etc\\hosts", systemDirectory
);
1851 err
= HostsFileOpen( &hFile
, hFileName
);
1852 require_noerr( err
, exit
);
1854 while ( HostsFileNext( hFile
, &node
) == 0 )
1856 if ( IsLocalName( node
) )
1858 node
->m_next
= gHostsFileInfo
;
1859 gHostsFileInfo
= node
;
1863 HostsFileInfoFree( node
);
1867 HostsFileClose( hFile
);
1870 for ( node
= gHostsFileInfo
; node
; node
= node
->m_next
)
1872 if ( IsSameName( node
, name
) )
1885 //===========================================================================================================================
1887 //===========================================================================================================================
1890 IsLocalName( HostsFileInfo
* node
)
1896 if ( strstr( node
->m_host
.h_name
, ".local" ) == NULL
)
1900 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1902 if ( strstr( node
->m_host
.h_aliases
[i
], ".local" ) )
1917 //===========================================================================================================================
1919 //===========================================================================================================================
1922 IsSameName( HostsFileInfo
* node
, const char * name
)
1929 if ( strcmp( node
->m_host
.h_name
, name
) != 0 )
1933 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1935 if ( strcmp( node
->m_host
.h_aliases
[i
], name
) == 0 )
1950 //===========================================================================================================================
1952 //===========================================================================================================================
1954 DEBUG_LOCAL OSStatus
1955 HostsFileOpen( HostsFile
** self
, const char * fname
)
1957 OSStatus err
= kNoErr
;
1959 *self
= (HostsFile
*) malloc( sizeof( HostsFile
) );
1960 require_action( *self
, exit
, err
= kNoMemoryErr
);
1961 memset( *self
, 0, sizeof( HostsFile
) );
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
);
1969 (*self
)->m_fp
= fopen( fname
, "r" );
1970 require_action( (*self
)->m_fp
, exit
, err
= kUnknownErr
);
1976 HostsFileClose( *self
);
1984 //===========================================================================================================================
1986 //===========================================================================================================================
1988 DEBUG_LOCAL OSStatus
1989 HostsFileClose( HostsFile
* self
)
1993 if ( self
->m_buffer
)
1995 free( self
->m_buffer
);
1996 self
->m_buffer
= NULL
;
2001 fclose( self
->m_fp
);
2011 //===========================================================================================================================
2012 // HostsFileInfoFree
2013 //===========================================================================================================================
2016 HostsFileInfoFree( HostsFileInfo
* info
)
2020 HostsFileInfo
* next
= info
->m_next
;
2022 if ( info
->m_host
.h_addr_list
)
2024 if ( info
->m_host
.h_addr_list
[0] )
2026 free( info
->m_host
.h_addr_list
[0] );
2027 info
->m_host
.h_addr_list
[0] = NULL
;
2030 free( info
->m_host
.h_addr_list
);
2031 info
->m_host
.h_addr_list
= NULL
;
2034 if ( info
->m_host
.h_aliases
)
2038 for ( i
= 0; info
->m_host
.h_aliases
[i
]; i
++ )
2040 free( info
->m_host
.h_aliases
[i
] );
2043 free( info
->m_host
.h_aliases
);
2046 if ( info
->m_host
.h_name
)
2048 free( info
->m_host
.h_name
);
2049 info
->m_host
.h_name
= NULL
;
2059 //===========================================================================================================================
2061 //===========================================================================================================================
2063 DEBUG_LOCAL OSStatus
2064 HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
)
2066 struct sockaddr_in6 addr_6
;
2067 struct sockaddr_in addr_4
;
2068 int numAliases
= ALIASES_INITIAL_SIZE
;
2076 OSStatus err
= kNoErr
;
2079 check( self
->m_fp
);
2084 *hInfo
= (HostsFileInfo
*) malloc( sizeof( HostsFileInfo
) );
2085 require_action( *hInfo
, exit
, err
= kNoMemoryErr
);
2086 memset( *hInfo
, 0, sizeof( HostsFileInfo
) );
2090 line
= fgets( self
->m_buffer
+ idx
, self
->m_bufferSize
- idx
, self
->m_fp
);
2098 // If there's no eol and no eof, then we didn't get the whole line
2100 if ( !strchr( line
, '\n' ) && !feof( self
->m_fp
) )
2105 /* Try and allocate space for longer line */
2107 bufferSize
= self
->m_bufferSize
* 2;
2108 buffer
= (char*) realloc( self
->m_buffer
, bufferSize
);
2109 require_action( buffer
, exit
, err
= kNoMemoryErr
);
2110 self
->m_bufferSize
= bufferSize
;
2111 self
->m_buffer
= buffer
;
2112 idx
= (int) strlen( self
->m_buffer
);
2117 line
= self
->m_buffer
;
2125 // Get rid of either comments or eol characters
2127 if (( tok
= strpbrk(line
, "#\n")) != NULL
)
2132 // Make sure there is some whitespace on this line
2134 if (( tok
= strpbrk(line
, " \t")) == NULL
)
2139 // Create two strings, where p == the IP Address and tok is the name list
2143 while ( *tok
== ' ' || *tok
== '\t')
2148 // Now we have the name
2150 len
= strlen( tok
) + 1;
2151 (*hInfo
)->m_host
.h_name
= (char*) malloc( len
);
2152 require_action( (*hInfo
)->m_host
.h_name
, exit
, err
= kNoMemoryErr
);
2153 strcpy_s( (*hInfo
)->m_host
.h_name
, len
, tok
);
2155 // Now create the address (IPv6/IPv4)
2157 addr_6
.sin6_family
= family
= AF_INET6
;
2158 dwSize
= sizeof( addr_6
);
2160 if ( WSAStringToAddress( line
, AF_INET6
, NULL
, ( struct sockaddr
*) &addr_6
, &dwSize
) != 0 )
2162 addr_4
.sin_family
= family
= AF_INET
;
2163 dwSize
= sizeof( addr_4
);
2165 if (WSAStringToAddress( line
, AF_INET
, NULL
, ( struct sockaddr
*) &addr_4
, &dwSize
) != 0 )
2171 (*hInfo
)->m_host
.h_addr_list
= (char**) malloc( sizeof( char**) * 2 );
2172 require_action( (*hInfo
)->m_host
.h_addr_list
, exit
, err
= kNoMemoryErr
);
2174 if ( family
== AF_INET6
)
2176 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_6
.sin6_addr
);
2177 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2178 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2179 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_6
.sin6_addr
, sizeof( addr_6
.sin6_addr
) );
2184 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_4
.sin_addr
);
2185 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2186 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2187 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_4
.sin_addr
, sizeof( addr_4
.sin_addr
) );
2190 (*hInfo
)->m_host
.h_addr_list
[1] = NULL
;
2191 (*hInfo
)->m_host
.h_addrtype
= family
;
2193 // Now get the aliases
2195 if ((tok
= strpbrk(tok
, " \t")) != NULL
)
2202 (*hInfo
)->m_host
.h_aliases
= (char**) malloc( sizeof(char**) * numAliases
);
2203 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2204 (*hInfo
)->m_host
.h_aliases
[0] = NULL
;
2206 while ( tok
&& *tok
)
2208 // Skip over the whitespace, waiting for the start of the next alias name
2210 if (*tok
== ' ' || *tok
== '\t')
2216 // Check to make sure we don't exhaust the alias buffer
2218 if ( i
>= ( numAliases
- 1 ) )
2220 numAliases
= numAliases
* 2;
2221 (*hInfo
)->m_host
.h_aliases
= (char**) realloc( (*hInfo
)->m_host
.h_aliases
, numAliases
* sizeof( char** ) );
2222 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2225 len
= strlen( tok
) + 1;
2226 (*hInfo
)->m_host
.h_aliases
[i
] = (char*) malloc( len
);
2227 require_action( (*hInfo
)->m_host
.h_aliases
[i
], exit
, err
= kNoMemoryErr
);
2229 strcpy_s( (*hInfo
)->m_host
.h_aliases
[i
], len
, tok
);
2231 if (( tok
= strpbrk( tok
, " \t")) != NULL
)
2236 (*hInfo
)->m_host
.h_aliases
[++i
] = NULL
;
2244 if ( err
&& ( *hInfo
) )
2246 HostsFileInfoFree( *hInfo
);
2254 #ifdef ENABLE_REVERSE_LOOKUP
2255 //===========================================================================================================================
2257 //===========================================================================================================================
2259 DEBUG_LOCAL OSStatus
2260 IsReverseLookup( LPCWSTR name
, size_t size
)
2263 OSStatus err
= kNoErr
;
2265 // IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa
2266 require_action_quiet( size
> sizeof_string( ".0.8.e.f.ip6.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2268 p
= name
+ ( size
- 1 );
2269 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
2271 if ( ( ( p
[ 0 ] != '.' ) ||
2272 ( ( p
[ 1 ] != '0' ) ) ||
2273 ( ( p
[ 2 ] != '.' ) ) ||
2274 ( ( p
[ 3 ] != '8' ) ) ||
2275 ( ( p
[ 4 ] != '.' ) ) ||
2276 ( ( p
[ 5 ] != 'E' ) && ( p
[ 5 ] != 'e' ) ) ||
2277 ( ( p
[ 6 ] != '.' ) ) ||
2278 ( ( p
[ 7 ] != 'F' ) && ( p
[ 7 ] != 'f' ) ) ||
2279 ( ( p
[ 8 ] != '.' ) ) ||
2280 ( ( p
[ 9 ] != 'I' ) && ( p
[ 9 ] != 'i' ) ) ||
2281 ( ( p
[ 10 ] != 'P' ) && ( p
[ 10 ] != 'p' ) ) ||
2282 ( ( p
[ 11 ] != '6' ) ) ||
2283 ( ( p
[ 12 ] != '.' ) ) ||
2284 ( ( p
[ 13 ] != 'A' ) && ( p
[ 13 ] != 'a' ) ) ||
2285 ( ( p
[ 14 ] != 'R' ) && ( p
[ 14 ] != 'r' ) ) ||
2286 ( ( p
[ 15 ] != 'P' ) && ( p
[ 15 ] != 'p' ) ) ||
2287 ( ( p
[ 16 ] != 'A' ) && ( p
[ 16 ] != 'a' ) ) ) )
2289 require_action_quiet( size
> sizeof_string( ".254.169.in-addr.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2291 p
= name
+ ( size
- 1 );
2292 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
2294 require_action_quiet( ( ( p
[ 0 ] == '.' ) &&
2295 ( ( p
[ 1 ] == '2' ) ) &&
2296 ( ( p
[ 2 ] == '5' ) ) &&
2297 ( ( p
[ 3 ] == '4' ) ) &&
2298 ( ( p
[ 4 ] == '.' ) ) &&
2299 ( ( p
[ 5 ] == '1' ) ) &&
2300 ( ( p
[ 6 ] == '6' ) ) &&
2301 ( ( p
[ 7 ] == '9' ) ) &&
2302 ( ( p
[ 8 ] == '.' ) ) &&
2303 ( ( p
[ 9 ] == 'I' ) || ( p
[ 9 ] == 'i' ) ) &&
2304 ( ( p
[ 10 ] == 'N' ) || ( p
[ 10 ] == 'n' ) ) &&
2305 ( ( p
[ 11 ] == '-' ) ) &&
2306 ( ( p
[ 12 ] == 'A' ) || ( p
[ 12 ] == 'a' ) ) &&
2307 ( ( p
[ 13 ] == 'D' ) || ( p
[ 13 ] == 'd' ) ) &&
2308 ( ( p
[ 14 ] == 'D' ) || ( p
[ 14 ] == 'd' ) ) &&
2309 ( ( p
[ 15 ] == 'R' ) || ( p
[ 15 ] == 'r' ) ) &&
2310 ( ( p
[ 16 ] == '.' ) ) &&
2311 ( ( p
[ 17 ] == 'A' ) || ( p
[ 17 ] == 'a' ) ) &&
2312 ( ( p
[ 18 ] == 'R' ) || ( p
[ 18 ] == 'r' ) ) &&
2313 ( ( p
[ 19 ] == 'P' ) || ( p
[ 19 ] == 'p' ) ) &&
2314 ( ( p
[ 20 ] == 'A' ) || ( p
[ 20 ] == 'a' ) ) ),
2315 exit
, err
= WSASERVICE_NOT_FOUND
);
2318 // It's a reverse lookup
2320 check( err
== kNoErr
);
2328 //===========================================================================================================================
2330 //===========================================================================================================================
2333 GetScopeId( DWORD ifIndex
)
2338 struct ifaddrs
* head
;
2339 struct ifaddrs
** next
;
2340 IP_ADAPTER_ADDRESSES
* iaaList
;
2342 IP_ADAPTER_ADDRESSES
* iaa
;
2349 require( gGetAdaptersAddressesFunctionPtr
, exit
);
2351 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
2352 // This loops to handle the case where the interface changes in the window after getting the size, but before the
2353 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
2355 flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
2360 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
2361 check( err
== ERROR_BUFFER_OVERFLOW
);
2362 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
2364 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
2365 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
2367 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
2368 if( err
== ERROR_SUCCESS
) break;
2373 require( i
< 100, exit
);
2374 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
2377 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
2381 if ( iaa
->IfIndex
> 0xFFFFFF )
2385 if ( iaa
->Ipv6IfIndex
> 0xFF )
2390 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
2391 // following code to crash when iterating through the prefix list. This seems
2392 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
2393 // This shouldn't happen according to Microsoft docs which states:
2395 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
2397 // So the data structure seems to be corrupted when we return from
2398 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
2399 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
2400 // modify iaa to have the correct values.
2402 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
2404 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
2411 // Skip psuedo and tunnel interfaces.
2413 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
2418 if ( iaa
->IfIndex
== ifIndex
)
2420 scopeId
= iaa
->Ipv6IfIndex
;