2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.14 2005/03/29 20:35:28 shersche
27 <rdar://problem/4053899> Remove reverse lookup implementation due to NSP framework limitation
29 Revision 1.13 2005/03/29 19:42:47 shersche
30 Do label check before checking etc/hosts file
32 Revision 1.12 2005/03/21 00:42:45 shersche
33 <rdar://problem/4021486> Fix build warnings on Win32 platform
35 Revision 1.11 2005/03/16 03:04:51 shersche
36 <rdar://problem/4050633> Don't issue multicast query multilabel dot-local names
38 Revision 1.10 2005/02/23 22:16:07 shersche
39 Unregister the NSP before registering to workaround an installer problem during upgrade installs
41 Revision 1.9 2005/02/01 01:45:55 shersche
42 Change mdnsNSP timeout to 2 seconds
44 Revision 1.8 2005/01/31 23:27:25 shersche
45 <rdar://problem/3936771> Don't try and resolve .local hostnames that are referenced in the hosts file
47 Revision 1.7 2005/01/28 23:50:13 shersche
48 <rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
51 Revision 1.6 2004/12/06 01:56:53 shersche
52 <rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
55 Revision 1.5 2004/07/13 21:24:28 rpantos
56 Fix for <rdar://problem/3701120>.
58 Revision 1.4 2004/07/09 18:03:33 shersche
59 removed extraneous DNSServiceQueryRecord call
61 Revision 1.3 2004/07/07 17:03:49 shersche
62 <rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
65 Revision 1.2 2004/06/24 19:18:07 shersche
67 Submitted by: herscher
69 Revision 1.1 2004/06/18 04:13:44 rpantos
72 Revision 1.2 2004/04/08 09:43:43 bradley
73 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
75 Revision 1.1 2004/01/30 03:00:33 bradley
76 mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
77 .local name lookups using Multicast DNS in all Windows apps.
85 #include "CommonServices.h"
86 #include "DebugServices.h"
94 #pragma mark == Structures ==
97 //===========================================================================================================================
99 //===========================================================================================================================
101 typedef struct Query
* QueryRef
;
102 typedef struct Query Query
;
108 WSAQUERYSETW
* querySet
;
112 HANDLE waitHandles
[ 2 ];
114 DNSServiceRef resolver
;
115 char name
[ kDNSServiceMaxDomainName
];
121 #define BUFFER_INITIAL_SIZE 4192
122 #define ALIASES_INITIAL_SIZE 5
124 typedef struct HostsFile
132 typedef struct HostsFileInfo
134 struct hostent m_host
;
135 struct HostsFileInfo
* m_next
;
140 #pragma mark == Prototypes ==
143 //===========================================================================================================================
145 //===========================================================================================================================
149 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
150 STDAPI
DllRegisterServer( void );
151 STDAPI
DllRegisterServer( void );
156 int WSPAPI
NSPCleanup( LPGUID inProviderID
);
158 DEBUG_LOCAL
int WSPAPI
159 NSPLookupServiceBegin(
161 LPWSAQUERYSETW inQuerySet
,
162 LPWSASERVICECLASSINFOW inServiceClassInfo
,
164 LPHANDLE outLookup
);
166 DEBUG_LOCAL
int WSPAPI
167 NSPLookupServiceNext(
170 LPDWORD ioBufferLength
,
171 LPWSAQUERYSETW outResults
);
173 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
);
175 DEBUG_LOCAL
int WSPAPI
178 LPWSASERVICECLASSINFOW inServiceClassInfo
,
179 LPWSAQUERYSETW inRegInfo
,
180 WSAESETSERVICEOP inOperation
,
183 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
);
184 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
);
185 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioBufSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
);
189 #define NSPLock() EnterCriticalSection( &gLock );
190 #define NSPUnlock() LeaveCriticalSection( &gLock );
192 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
);
193 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
);
194 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
);
196 DEBUG_LOCAL
void CALLBACK_COMPAT
199 DNSServiceFlags inFlags
,
200 uint32_t inInterfaceIndex
,
201 DNSServiceErrorType inErrorCode
,
205 uint16_t inRDataSize
,
206 const void * inRData
,
213 const WSAQUERYSETW
* inQuerySet
,
214 DWORD inQuerySetFlags
,
215 WSAQUERYSETW
** outQuerySet
,
221 const WSAQUERYSETW
* inQuerySet
,
222 DWORD inQuerySetFlags
,
223 WSAQUERYSETW
* outQuerySet
);
225 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
);
228 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
);
230 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
232 #define dlog_query_set( LEVEL, SET )
235 DEBUG_LOCAL BOOL
InHostsTable( const char * name
);
236 DEBUG_LOCAL BOOL
IsLocalName( HostsFileInfo
* node
);
237 DEBUG_LOCAL BOOL
IsSameName( HostsFileInfo
* node
, const char * name
);
238 DEBUG_LOCAL OSStatus
HostsFileOpen( HostsFile
** self
, const char * fname
);
239 DEBUG_LOCAL OSStatus
HostsFileClose( HostsFile
* self
);
240 DEBUG_LOCAL
void HostsFileInfoFree( HostsFileInfo
* info
);
241 DEBUG_LOCAL OSStatus
HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
);
242 DEBUG_LOCAL
const char * GetNextLabel( const char *cstr
, char label
[64] );
244 #ifdef ENABLE_REVERSE_LOOKUP
245 DEBUG_LOCAL OSStatus
IsReverseLookup( LPCWSTR name
, size_t size
);
250 #pragma mark == Globals ==
253 //===========================================================================================================================
255 //===========================================================================================================================
257 // {B600E6E9-553B-4a19-8696-335E5C896153}
258 DEBUG_LOCAL HINSTANCE gInstance
= NULL
;
259 DEBUG_LOCAL
wchar_t * gNSPName
= L
"mdnsNSP";
260 DEBUG_LOCAL GUID gNSPGUID
= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
261 DEBUG_LOCAL LONG gRefCount
= 0;
262 DEBUG_LOCAL CRITICAL_SECTION gLock
;
263 DEBUG_LOCAL
bool gLockInitialized
= false;
264 DEBUG_LOCAL
bool gDNSSDInitialized
= false;
265 DEBUG_LOCAL QueryRef gQueryList
= NULL
;
266 DEBUG_LOCAL HostsFileInfo
* gHostsFileInfo
= NULL
;
272 //===========================================================================================================================
274 //===========================================================================================================================
276 BOOL APIENTRY
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
)
278 DEBUG_USE_ONLY( inInstance
);
279 DEBUG_UNUSED( inReserved
);
283 case DLL_PROCESS_ATTACH
:
284 gInstance
= inInstance
;
285 gHostsFileInfo
= NULL
;
286 debug_initialize( kDebugOutputTypeWindowsEventLog
, "mDNS NSP", inInstance
);
287 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelInfo
);
288 dlog( kDebugLevelTrace
, "\n" );
289 dlog( kDebugLevelVerbose
, "%s: process attach\n", __ROUTINE__
);
292 case DLL_PROCESS_DETACH
:
293 HostsFileInfoFree( gHostsFileInfo
);
294 gHostsFileInfo
= NULL
;
295 dlog( kDebugLevelVerbose
, "%s: process detach\n", __ROUTINE__
);
298 case DLL_THREAD_ATTACH
:
299 dlog( kDebugLevelVerbose
, "%s: thread attach\n", __ROUTINE__
);
302 case DLL_THREAD_DETACH
:
303 dlog( kDebugLevelVerbose
, "%s: thread detach\n", __ROUTINE__
);
307 dlog( kDebugLevelNotice
, "%s: unknown reason code (%d)\n", __ROUTINE__
, inReason
);
314 //===========================================================================================================================
316 //===========================================================================================================================
318 STDAPI
DllRegisterServer( void )
321 WCHAR path
[ MAX_PATH
];
324 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
326 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
327 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
328 require_noerr( err
, exit
);
330 // Unregister before registering to workaround an installer
331 // problem during upgrade installs.
333 WSCUnInstallNameSpace( &gNSPGUID
);
335 err
= GetModuleFileNameW( gInstance
, path
, sizeof( path
) );
336 err
= translate_errno( err
!= 0, errno_compat(), kUnknownErr
);
337 require_noerr( err
, exit
);
339 err
= WSCInstallNameSpace( gNSPName
, path
, NS_DNS
, 1, &gNSPGUID
);
340 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
341 require_noerr( err
, exit
);
349 //===========================================================================================================================
350 // DllUnregisterServer
351 //===========================================================================================================================
353 STDAPI
DllUnregisterServer( void )
358 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
360 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
361 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
362 require_noerr( err
, exit
);
364 err
= WSCUnInstallNameSpace( &gNSPGUID
);
365 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
366 require_noerr( err
, exit
);
375 //===========================================================================================================================
378 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
379 //===========================================================================================================================
381 int WSPAPI
NSPStartup( LPGUID inProviderID
, LPNSP_ROUTINE outRoutines
)
385 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
386 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
388 // Only initialize if this is the first time NSPStartup is called.
390 if( InterlockedIncrement( &gRefCount
) != 1 )
396 // Initialize our internal state.
398 InitializeCriticalSection( &gLock
);
399 gLockInitialized
= true;
401 // Set the size to exclude NSPIoctl because we don't implement it.
403 outRoutines
->cbSize
= FIELD_OFFSET( NSP_ROUTINE
, NSPIoctl
);
404 outRoutines
->dwMajorVersion
= 4;
405 outRoutines
->dwMinorVersion
= 4;
406 outRoutines
->NSPCleanup
= NSPCleanup
;
407 outRoutines
->NSPLookupServiceBegin
= NSPLookupServiceBegin
;
408 outRoutines
->NSPLookupServiceNext
= NSPLookupServiceNext
;
409 outRoutines
->NSPLookupServiceEnd
= NSPLookupServiceEnd
;
410 outRoutines
->NSPSetService
= NSPSetService
;
411 outRoutines
->NSPInstallServiceClass
= NSPInstallServiceClass
;
412 outRoutines
->NSPRemoveServiceClass
= NSPRemoveServiceClass
;
413 outRoutines
->NSPGetServiceClassInfo
= NSPGetServiceClassInfo
;
418 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
419 if( err
!= NO_ERROR
)
421 NSPCleanup( inProviderID
);
422 SetLastError( (DWORD
) err
);
423 return( SOCKET_ERROR
);
428 //===========================================================================================================================
431 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
432 //===========================================================================================================================
434 int WSPAPI
NSPCleanup( LPGUID inProviderID
)
436 DEBUG_USE_ONLY( inProviderID
);
438 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
439 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
441 // Only initialize if this is the first time NSPStartup is called.
443 if( InterlockedDecrement( &gRefCount
) != 0 )
448 // Stop any outstanding queries.
450 if( gLockInitialized
)
456 check_string( gQueryList
->refCount
== 1, "NSPCleanup with outstanding queries!" );
457 QueryRelease( gQueryList
);
459 if( gLockInitialized
)
464 // Shut down DNS-SD and release our resources.
466 if( gDNSSDInitialized
)
468 gDNSSDInitialized
= false;
470 if( gLockInitialized
)
472 gLockInitialized
= false;
473 DeleteCriticalSection( &gLock
);
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
[128];
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 replyDomain
= translated
;
595 while ( *replyDomain
)
597 label
[labels
++] = replyDomain
;
598 replyDomain
= GetNextLabel(replyDomain
, text
);
601 require_action( labels
== 2, exit
, err
= WSASERVICE_NOT_FOUND
);
603 // <rdar://problem/3936771>
605 // Check to see if the name of this host is in the hosts table. If so,
606 // don't try and resolve it
608 require_action( InHostsTable( translated
) == FALSE
, exit
, err
= WSASERVICE_NOT_FOUND
);
611 // 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.
614 if( !gDNSSDInitialized
)
616 gDNSSDInitialized
= true;
619 err
= QueryCreate( inQuerySet
, inFlags
, &obj
);
621 require_noerr( err
, exit
);
623 *outLookup
= (HANDLE
) obj
;
626 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
627 if( err
!= NO_ERROR
)
629 SetLastError( (DWORD
) err
);
630 return( SOCKET_ERROR
);
635 //===========================================================================================================================
636 // NSPLookupServiceNext
638 // This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
639 // query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
640 // in the lpqsResults parameter.
641 //===========================================================================================================================
643 DEBUG_LOCAL
int WSPAPI
644 NSPLookupServiceNext(
648 LPWSAQUERYSETW outResults
)
655 DEBUG_USE_ONLY( inFlags
);
657 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
661 err
= QueryRetain( (QueryRef
) inLookup
);
662 require_noerr( err
, exit
);
663 obj
= (QueryRef
) inLookup
;
664 require_action( ioSize
, exit
, err
= WSAEINVAL
);
665 require_action( outResults
, exit
, err
= WSAEINVAL
);
667 dlog( kDebugLevelTrace
, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__
, inLookup
, inFlags
, *ioSize
);
669 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
672 waitResult
= WaitForMultipleObjects( obj
->waitCount
, obj
->waitHandles
, FALSE
, 2 * 1000 );
674 require_action_quiet( waitResult
!= ( WAIT_OBJECT_0
+ 1 ), exit
, err
= WSA_E_CANCELLED
);
675 err
= translate_errno( waitResult
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), WSASERVICE_NOT_FOUND
);
676 require_noerr_quiet( err
, exit
);
677 DNSServiceProcessResult(obj
->resolver
);
678 require_action_quiet( obj
->addrValid
, exit
, err
= WSA_E_NO_MORE
);
680 // Copy the externalized query results to the callers buffer (if it fits).
682 size
= QueryCopyQuerySetSize( obj
, obj
->querySet
, obj
->querySetFlags
);
683 require_action( size
<= (size_t) *ioSize
, exit
, err
= WSAEFAULT
);
685 QueryCopyQuerySetTo( obj
, obj
->querySet
, obj
->querySetFlags
, outResults
);
686 outResults
->dwOutputFlags
= RESULT_IS_ADDED
;
687 obj
->addrValid
= false;
695 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
696 if( err
!= NO_ERROR
)
698 SetLastError( (DWORD
) err
);
699 return( SOCKET_ERROR
);
704 //===========================================================================================================================
705 // NSPLookupServiceEnd
707 // This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
708 // indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
709 // allocated resources associated with the query.
710 //===========================================================================================================================
712 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
)
716 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
718 dlog( kDebugLevelTrace
, "%s (lookup=%#p)\n", __ROUTINE__
, inLookup
);
721 err
= QueryRelease( (QueryRef
) inLookup
);
723 require_noerr( err
, exit
);
726 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
727 if( err
!= NO_ERROR
)
729 SetLastError( (DWORD
) err
);
730 return( SOCKET_ERROR
);
735 //===========================================================================================================================
738 // This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
739 // deregister an instance of a server with our service. For registration, the user needs to associate the server with a
740 // service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
741 // contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
742 //===========================================================================================================================
744 DEBUG_LOCAL
int WSPAPI
747 LPWSASERVICECLASSINFOW inServiceClassInfo
,
748 LPWSAQUERYSETW inRegInfo
,
749 WSAESETSERVICEOP inOperation
,
752 DEBUG_UNUSED( inProviderID
);
753 DEBUG_UNUSED( inServiceClassInfo
);
754 DEBUG_UNUSED( inRegInfo
);
755 DEBUG_UNUSED( inOperation
);
756 DEBUG_UNUSED( inFlags
);
758 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
759 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
761 // We don't allow services to be registered so always return an error.
763 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
767 //===========================================================================================================================
768 // NSPInstallServiceClass
770 // This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
771 // is used to define certain characteristics for a group of services. After a service class is registered, an actual
772 // instance of a server may be registered.
773 //===========================================================================================================================
775 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
)
777 DEBUG_UNUSED( inProviderID
);
778 DEBUG_UNUSED( inServiceClassInfo
);
780 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
781 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
783 // We don't allow service classes to be installed so always return an error.
785 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
786 return( WSA_INVALID_PARAMETER
);
789 //===========================================================================================================================
790 // NSPRemoveServiceClass
792 // This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
793 // class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
795 //===========================================================================================================================
797 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
)
799 DEBUG_UNUSED( inProviderID
);
800 DEBUG_UNUSED( inServiceClassID
);
802 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
803 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
805 // We don't allow service classes to be installed so always return an error.
807 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
808 return( WSATYPE_NOT_FOUND
);
811 //===========================================================================================================================
812 // NSPGetServiceClassInfo
814 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
815 // a given service class.
816 //===========================================================================================================================
818 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
)
820 DEBUG_UNUSED( inProviderID
);
821 DEBUG_UNUSED( ioSize
);
822 DEBUG_UNUSED( ioServiceClassInfo
);
824 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
825 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
827 // We don't allow service classes to be installed so always return an error.
829 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
830 return( WSATYPE_NOT_FOUND
);
837 //===========================================================================================================================
840 // Warning: Assumes the NSP lock is held.
841 //===========================================================================================================================
843 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
)
847 char name
[ kDNSServiceMaxDomainName
];
853 check( inQuerySet
->lpszServiceInstanceName
);
856 // Convert the wchar_t name to UTF-8.
858 n
= WideCharToMultiByte( CP_UTF8
, 0, inQuerySet
->lpszServiceInstanceName
, -1, name
, sizeof( name
), NULL
, NULL
);
859 err
= translate_errno( n
> 0, (OSStatus
) GetLastError(), WSAEINVAL
);
860 require_noerr( err
, exit
);
862 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
864 obj
= (QueryRef
) calloc( 1, sizeof( *obj
) );
865 require_action( obj
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
869 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
) {} // Find the end of the list.
872 // Set up events to signal when data is ready and when cancelling.
874 obj
->dataEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
875 require_action( obj
->dataEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
877 obj
->cancelEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
878 require_action( obj
->cancelEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
882 err
= DNSServiceQueryRecord( &obj
->resolver
, 0, 0, name
, kDNSServiceType_A
, kDNSServiceClass_IN
,
883 QueryRecordCallback
, obj
);
884 require_noerr( err
, exit
);
886 // Attach the socket to the event
888 WSAEventSelect(DNSServiceRefSockFD(obj
->resolver
), obj
->dataEvent
, FD_READ
|FD_CLOSE
);
891 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->dataEvent
;
892 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->cancelEvent
;
893 check( obj
->waitCount
== sizeof_array( obj
->waitHandles
) );
895 // Copy the QuerySet so it can be returned later.
897 obj
->querySetFlags
= inQuerySetFlags
;
898 inQuerySetFlags
= ( inQuerySetFlags
& ~( LUP_RETURN_ADDR
| LUP_RETURN_BLOB
) ) | LUP_RETURN_NAME
;
899 err
= QueryCopyQuerySet( obj
, inQuerySet
, inQuerySetFlags
, &obj
->querySet
, &obj
->querySetSize
);
900 require_noerr( err
, exit
);
916 //===========================================================================================================================
919 // Warning: Assumes the NSP lock is held.
920 //===========================================================================================================================
922 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
)
927 for( obj
= gQueryList
; obj
; obj
= obj
->next
)
934 require_action( obj
, exit
, err
= WSA_INVALID_HANDLE
);
943 //===========================================================================================================================
946 // Warning: Assumes the NSP lock is held.
947 //===========================================================================================================================
949 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
)
955 // Find the item in the list.
957 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
)
964 require_action( *p
, exit
, err
= WSA_INVALID_HANDLE
);
966 // Signal a cancel to unblock any threads waiting for results.
968 if( inRef
->cancelEvent
)
970 ok
= SetEvent( inRef
->cancelEvent
);
971 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
976 if( inRef
->resolver
)
978 DNSServiceRefDeallocate( inRef
->resolver
);
979 inRef
->resolver
= NULL
;
982 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
984 if( --inRef
->refCount
!= 0 )
991 // Release resources.
993 if( inRef
->cancelEvent
)
995 ok
= CloseHandle( inRef
->cancelEvent
);
996 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
998 if( inRef
->dataEvent
)
1000 ok
= CloseHandle( inRef
->dataEvent
);
1001 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1003 if( inRef
->querySet
)
1005 free( inRef
->querySet
);
1014 //===========================================================================================================================
1015 // QueryRecordCallback
1016 //===========================================================================================================================
1018 DEBUG_LOCAL
void CALLBACK_COMPAT
1019 QueryRecordCallback(
1020 DNSServiceRef inRef
,
1021 DNSServiceFlags inFlags
,
1022 uint32_t inInterfaceIndex
,
1023 DNSServiceErrorType inErrorCode
,
1024 const char * inName
,
1027 uint16_t inRDataSize
,
1028 const void * inRData
,
1037 DEBUG_UNUSED( inFlags
);
1038 DEBUG_UNUSED( inInterfaceIndex
);
1039 DEBUG_UNUSED( inTTL
);
1042 obj
= (QueryRef
) inContext
;
1044 require_noerr( inErrorCode
, exit
);
1045 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1046 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1047 require( inRRType
== kDNSServiceType_A
, exit
);
1048 require( inRDataSize
== 4, exit
);
1050 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1051 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1053 // Copy the name if needed.
1055 if( obj
->name
[ 0 ] == '\0' )
1059 while( *src
!= '\0' )
1064 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1065 check( obj
->nameSize
< sizeof( obj
->name
) );
1070 memcpy( &obj
->addr
, inRData
, inRDataSize
);
1071 obj
->addrValid
= true;
1073 // Signal that a result is ready.
1075 check( obj
->dataEvent
);
1076 ok
= SetEvent( obj
->dataEvent
);
1077 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1079 // Stop the resolver after the first response.
1081 DNSServiceRefDeallocate( inRef
);
1082 obj
->resolver
= NULL
;
1092 //===========================================================================================================================
1093 // QueryCopyQuerySet
1095 // Warning: Assumes the NSP lock is held.
1096 //===========================================================================================================================
1098 DEBUG_LOCAL OSStatus
1101 const WSAQUERYSETW
* inQuerySet
,
1102 DWORD inQuerySetFlags
,
1103 WSAQUERYSETW
** outQuerySet
,
1110 check( inQuerySet
);
1111 check( outQuerySet
);
1113 size
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1114 qs
= (WSAQUERYSETW
*) calloc( 1, size
);
1115 require_action( qs
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1117 QueryCopyQuerySetTo( inRef
, inQuerySet
, inQuerySetFlags
, qs
);
1135 //===========================================================================================================================
1136 // QueryCopyQuerySetTo
1138 // Warning: Assumes the NSP lock is held.
1139 //===========================================================================================================================
1142 QueryCopyQuerySetTo(
1144 const WSAQUERYSETW
* inQuerySet
,
1145 DWORD inQuerySetFlags
,
1146 WSAQUERYSETW
* outQuerySet
)
1157 debugSize
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1160 check( inQuerySet
);
1161 check( outQuerySet
);
1163 dst
= (uint8_t *) outQuerySet
;
1165 // Copy the static portion of the results.
1167 *outQuerySet
= *inQuerySet
;
1168 dst
+= sizeof( *inQuerySet
);
1170 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1172 s
= inQuerySet
->lpszServiceInstanceName
;
1175 outQuerySet
->lpszServiceInstanceName
= (LPWSTR
) dst
;
1177 while( ( *q
++ = *s
++ ) != 0 ) {}
1178 dst
= (uint8_t *) q
;
1183 outQuerySet
->lpszServiceInstanceName
= NULL
;
1186 if( inQuerySet
->lpServiceClassId
)
1188 outQuerySet
->lpServiceClassId
= (LPGUID
) dst
;
1189 *outQuerySet
->lpServiceClassId
= *inQuerySet
->lpServiceClassId
;
1190 dst
+= sizeof( *inQuerySet
->lpServiceClassId
);
1193 if( inQuerySet
->lpVersion
)
1195 outQuerySet
->lpVersion
= (LPWSAVERSION
) dst
;
1196 *outQuerySet
->lpVersion
= *inQuerySet
->lpVersion
;
1197 dst
+= sizeof( *inQuerySet
->lpVersion
);
1200 s
= inQuerySet
->lpszComment
;
1203 outQuerySet
->lpszComment
= (LPWSTR
) dst
;
1205 while( ( *q
++ = *s
++ ) != 0 ) {}
1206 dst
= (uint8_t *) q
;
1209 if( inQuerySet
->lpNSProviderId
)
1211 outQuerySet
->lpNSProviderId
= (LPGUID
) dst
;
1212 *outQuerySet
->lpNSProviderId
= *inQuerySet
->lpNSProviderId
;
1213 dst
+= sizeof( *inQuerySet
->lpNSProviderId
);
1216 s
= inQuerySet
->lpszContext
;
1219 outQuerySet
->lpszContext
= (LPWSTR
) dst
;
1221 while( ( *q
++ = *s
++ ) != 0 ) {}
1222 dst
= (uint8_t *) q
;
1225 n
= inQuerySet
->dwNumberOfProtocols
;
1228 check( inQuerySet
->lpafpProtocols
);
1230 outQuerySet
->lpafpProtocols
= (LPAFPROTOCOLS
) dst
;
1231 for( i
= 0; i
< n
; ++i
)
1233 outQuerySet
->lpafpProtocols
[ i
] = inQuerySet
->lpafpProtocols
[ i
];
1234 dst
+= sizeof( *inQuerySet
->lpafpProtocols
);
1238 s
= inQuerySet
->lpszQueryString
;
1241 outQuerySet
->lpszQueryString
= (LPWSTR
) dst
;
1243 while( ( *q
++ = *s
++ ) != 0 ) {}
1244 dst
= (uint8_t *) q
;
1247 // Copy the address(es).
1249 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addrValid
)
1251 struct sockaddr_in
* addr
;
1253 outQuerySet
->dwNumberOfCsAddrs
= 1;
1254 outQuerySet
->lpcsaBuffer
= (LPCSADDR_INFO
) dst
;
1255 dst
+= sizeof( *outQuerySet
->lpcsaBuffer
);
1257 outQuerySet
->lpcsaBuffer
[ 0 ].LocalAddr
.lpSockaddr
= NULL
;
1258 outQuerySet
->lpcsaBuffer
[ 0 ].LocalAddr
.iSockaddrLength
= 0;
1260 outQuerySet
->lpcsaBuffer
[ 0 ].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1261 outQuerySet
->lpcsaBuffer
[ 0 ].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in
);
1263 addr
= (struct sockaddr_in
*) dst
;
1264 memset( addr
, 0, sizeof( *addr
) );
1265 addr
->sin_family
= AF_INET
;
1266 memcpy( &addr
->sin_addr
, &inRef
->addr
, 4 );
1267 dst
+= sizeof( *addr
);
1269 outQuerySet
->lpcsaBuffer
[ 0 ].iSocketType
= AF_INET
; // Emulate Tcpip NSP
1270 outQuerySet
->lpcsaBuffer
[ 0 ].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1274 outQuerySet
->dwNumberOfCsAddrs
= 0;
1275 outQuerySet
->lpcsaBuffer
= NULL
;
1278 // Copy the hostent blob.
1280 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addrValid
)
1283 struct hostent
* he
;
1286 outQuerySet
->lpBlob
= (LPBLOB
) dst
;
1287 dst
+= sizeof( *outQuerySet
->lpBlob
);
1290 he
= (struct hostent
*) dst
;
1291 dst
+= sizeof( *he
);
1293 he
->h_name
= (char *)( dst
- base
);
1294 memcpy( dst
, inRef
->name
, inRef
->nameSize
+ 1 );
1295 dst
+= ( inRef
->nameSize
+ 1 );
1297 he
->h_aliases
= (char **)( dst
- base
);
1298 p
= (uintptr_t *) dst
;
1300 dst
= (uint8_t *) p
;
1302 he
->h_addrtype
= AF_INET
;
1305 he
->h_addr_list
= (char **)( dst
- base
);
1306 p
= (uintptr_t *) dst
;
1307 dst
+= ( 2 * sizeof( *p
) );
1308 *p
++ = (uintptr_t)( dst
- base
);
1310 p
= (uintptr_t *) dst
;
1311 *p
++ = (uintptr_t) inRef
->addr
;
1312 dst
= (uint8_t *) p
;
1314 outQuerySet
->lpBlob
->cbSize
= (ULONG
)( dst
- base
);
1315 outQuerySet
->lpBlob
->pBlobData
= (BYTE
*) base
;
1317 dlog_query_set( kDebugLevelVerbose
, outQuerySet
);
1319 check( (size_t)( dst
- ( (uint8_t *) outQuerySet
) ) == debugSize
);
1322 //===========================================================================================================================
1323 // QueryCopyQuerySetSize
1325 // Warning: Assumes the NSP lock is held.
1326 //===========================================================================================================================
1328 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
)
1335 check( inQuerySet
);
1337 // Calculate the size of the static portion of the results.
1339 size
= sizeof( *inQuerySet
);
1341 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1343 s
= inQuerySet
->lpszServiceInstanceName
;
1346 for( p
= s
; *p
; ++p
) {}
1347 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1351 if( inQuerySet
->lpServiceClassId
)
1353 size
+= sizeof( *inQuerySet
->lpServiceClassId
);
1356 if( inQuerySet
->lpVersion
)
1358 size
+= sizeof( *inQuerySet
->lpVersion
);
1361 s
= inQuerySet
->lpszComment
;
1364 for( p
= s
; *p
; ++p
) {}
1365 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1368 if( inQuerySet
->lpNSProviderId
)
1370 size
+= sizeof( *inQuerySet
->lpNSProviderId
);
1373 s
= inQuerySet
->lpszContext
;
1376 for( p
= s
; *p
; ++p
) {}
1377 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1380 size
+= ( inQuerySet
->dwNumberOfProtocols
* sizeof( *inQuerySet
->lpafpProtocols
) );
1382 s
= inQuerySet
->lpszQueryString
;
1385 for( p
= s
; *p
; ++p
) {}
1386 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1389 // Calculate the size of the address(es).
1391 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addrValid
)
1393 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1394 size
+= sizeof( struct sockaddr_in
);
1397 // Calculate the size of the hostent blob.
1399 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addrValid
)
1401 size
+= sizeof( *inQuerySet
->lpBlob
); // Blob ptr/size structure
1402 size
+= sizeof( struct hostent
); // Old-style hostent structure
1403 size
+= ( inRef
->nameSize
+ 1 ); // Name and null terminator
1404 size
+= 4; // Alias list terminator (0 offset)
1405 size
+= 4; // Offset to address.
1406 size
+= 4; // Address list terminator (0 offset)
1407 size
+= 4; // IPv4 address
1417 //===========================================================================================================================
1418 // DebugDumpQuerySet
1419 //===========================================================================================================================
1421 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1422 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1424 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1425 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1427 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1429 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
)
1433 check( inQuerySet
);
1435 // Fixed portion of the QuerySet.
1437 dlog( inLevel
, "QuerySet:\n" );
1438 dlog( inLevel
, " dwSize: %d (expected %d)\n", inQuerySet
->dwSize
, sizeof( *inQuerySet
) );
1439 if( inQuerySet
->lpszServiceInstanceName
)
1441 dlog( inLevel
, " lpszServiceInstanceName: %S\n", inQuerySet
->lpszServiceInstanceName
);
1445 dlog( inLevel
, " lpszServiceInstanceName: <null>\n" );
1447 if( inQuerySet
->lpServiceClassId
)
1449 dlog( inLevel
, " lpServiceClassId: %U\n", inQuerySet
->lpServiceClassId
);
1453 dlog( inLevel
, " lpServiceClassId: <null>\n" );
1455 if( inQuerySet
->lpVersion
)
1457 dlog( inLevel
, " lpVersion:\n" );
1458 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->dwVersion
);
1459 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->ecHow
);
1463 dlog( inLevel
, " lpVersion: <null>\n" );
1465 if( inQuerySet
->lpszComment
)
1467 dlog( inLevel
, " lpszComment: %S\n", inQuerySet
->lpszComment
);
1471 dlog( inLevel
, " lpszComment: <null>\n" );
1473 dlog( inLevel
, " dwNameSpace: %d %s\n", inQuerySet
->dwNameSpace
,
1474 DebugNameSpaceToString( inQuerySet
->dwNameSpace
) );
1475 if( inQuerySet
->lpNSProviderId
)
1477 dlog( inLevel
, " lpNSProviderId: %U\n", inQuerySet
->lpNSProviderId
);
1481 dlog( inLevel
, " lpNSProviderId: <null>\n" );
1483 if( inQuerySet
->lpszContext
)
1485 dlog( inLevel
, " lpszContext: %S\n", inQuerySet
->lpszContext
);
1489 dlog( inLevel
, " lpszContext: <null>\n" );
1491 dlog( inLevel
, " dwNumberOfProtocols: %d\n", inQuerySet
->dwNumberOfProtocols
);
1492 dlog( inLevel
, " lpafpProtocols: %s\n", inQuerySet
->lpafpProtocols
? "" : "<null>" );
1493 for( i
= 0; i
< inQuerySet
->dwNumberOfProtocols
; ++i
)
1497 dlog( inLevel
, "\n" );
1499 dlog( inLevel
, " iAddressFamily: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
,
1500 DebugSocketFamilyToString( inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
) );
1501 dlog( inLevel
, " iProtocol: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iProtocol
,
1502 DebugSocketProtocolToString( inQuerySet
->lpafpProtocols
[ i
].iProtocol
) );
1504 if( inQuerySet
->lpszQueryString
)
1506 dlog( inLevel
, " lpszQueryString: %S\n", inQuerySet
->lpszQueryString
);
1510 dlog( inLevel
, " lpszQueryString: <null>\n" );
1512 dlog( inLevel
, " dwNumberOfCsAddrs: %d\n", inQuerySet
->dwNumberOfCsAddrs
);
1513 dlog( inLevel
, " lpcsaBuffer: %s\n", inQuerySet
->lpcsaBuffer
? "" : "<null>" );
1514 for( i
= 0; i
< inQuerySet
->dwNumberOfCsAddrs
; ++i
)
1518 dlog( inLevel
, "\n" );
1520 if( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
&&
1521 ( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.iSockaddrLength
> 0 ) )
1523 dlog( inLevel
, " LocalAddr: %##a\n",
1524 inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
);
1528 dlog( inLevel
, " LocalAddr: <null/empty>\n" );
1530 if( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
&&
1531 ( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.iSockaddrLength
> 0 ) )
1533 dlog( inLevel
, " RemoteAddr: %##a\n",
1534 inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
);
1538 dlog( inLevel
, " RemoteAddr: <null/empty>\n" );
1540 dlog( inLevel
, " iSocketType: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iSocketType
);
1541 dlog( inLevel
, " iProtocol: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iProtocol
);
1543 dlog( inLevel
, " dwOutputFlags: %d\n", inQuerySet
->dwOutputFlags
);
1545 // Blob portion of the QuerySet.
1547 if( inQuerySet
->lpBlob
)
1549 dlog( inLevel
, " lpBlob:\n" );
1550 dlog( inLevel
, " cbSize: %ld\n", inQuerySet
->lpBlob
->cbSize
);
1551 dlog( inLevel
, " pBlobData: %#p\n", inQuerySet
->lpBlob
->pBlobData
);
1552 dloghex( inLevel
, 12, NULL
, 0, 0, NULL
, 0,
1553 inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->cbSize
,
1554 kDebugFlagsNone
, NULL
, 0 );
1558 dlog( inLevel
, " lpBlob: <null>\n" );
1564 //===========================================================================================================================
1566 //===========================================================================================================================
1569 InHostsTable( const char * name
)
1571 HostsFileInfo
* node
;
1577 if ( gHostsFileInfo
== NULL
)
1579 TCHAR systemDirectory
[MAX_PATH
];
1580 TCHAR hFileName
[MAX_PATH
];
1583 GetSystemDirectory( systemDirectory
, sizeof( systemDirectory
) );
1584 sprintf( hFileName
, "%s\\drivers\\etc\\hosts", systemDirectory
);
1585 err
= HostsFileOpen( &hFile
, hFileName
);
1586 require_noerr( err
, exit
);
1588 while ( HostsFileNext( hFile
, &node
) == 0 )
1590 if ( IsLocalName( node
) )
1592 node
->m_next
= gHostsFileInfo
;
1593 gHostsFileInfo
= node
;
1597 HostsFileInfoFree( node
);
1601 HostsFileClose( hFile
);
1604 for ( node
= gHostsFileInfo
; node
; node
= node
->m_next
)
1606 if ( IsSameName( node
, name
) )
1619 //===========================================================================================================================
1621 //===========================================================================================================================
1624 IsLocalName( HostsFileInfo
* node
)
1630 if ( strstr( node
->m_host
.h_name
, ".local" ) == NULL
)
1634 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1636 if ( strstr( node
->m_host
.h_aliases
[i
], ".local" ) )
1651 //===========================================================================================================================
1653 //===========================================================================================================================
1656 IsSameName( HostsFileInfo
* node
, const char * name
)
1663 if ( strcmp( node
->m_host
.h_name
, name
) != 0 )
1667 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1669 if ( strcmp( node
->m_host
.h_aliases
[i
], name
) == 0 )
1684 //===========================================================================================================================
1686 //===========================================================================================================================
1688 DEBUG_LOCAL OSStatus
1689 HostsFileOpen( HostsFile
** self
, const char * fname
)
1691 OSStatus err
= kNoErr
;
1693 *self
= (HostsFile
*) malloc( sizeof( HostsFile
) );
1694 require_action( *self
, exit
, err
= kNoMemoryErr
);
1695 memset( *self
, 0, sizeof( HostsFile
) );
1697 (*self
)->m_bufferSize
= BUFFER_INITIAL_SIZE
;
1698 (*self
)->m_buffer
= (char*) malloc( (*self
)->m_bufferSize
);
1699 require_action( (*self
)->m_buffer
, exit
, err
= kNoMemoryErr
);
1703 (*self
)->m_fp
= fopen( fname
, "r" );
1704 require_action( (*self
)->m_fp
, exit
, err
= kUnknownErr
);
1710 HostsFileClose( *self
);
1718 //===========================================================================================================================
1720 //===========================================================================================================================
1722 DEBUG_LOCAL OSStatus
1723 HostsFileClose( HostsFile
* self
)
1727 if ( self
->m_buffer
)
1729 free( self
->m_buffer
);
1730 self
->m_buffer
= NULL
;
1735 fclose( self
->m_fp
);
1745 //===========================================================================================================================
1746 // HostsFileInfoFree
1747 //===========================================================================================================================
1750 HostsFileInfoFree( HostsFileInfo
* info
)
1754 HostsFileInfo
* next
= info
->m_next
;
1756 if ( info
->m_host
.h_addr_list
)
1758 if ( info
->m_host
.h_addr_list
[0] )
1760 free( info
->m_host
.h_addr_list
[0] );
1761 info
->m_host
.h_addr_list
[0] = NULL
;
1764 free( info
->m_host
.h_addr_list
);
1765 info
->m_host
.h_addr_list
= NULL
;
1768 if ( info
->m_host
.h_aliases
)
1772 for ( i
= 0; info
->m_host
.h_aliases
[i
]; i
++ )
1774 free( info
->m_host
.h_aliases
[i
] );
1777 free( info
->m_host
.h_aliases
);
1780 if ( info
->m_host
.h_name
)
1782 free( info
->m_host
.h_name
);
1783 info
->m_host
.h_name
= NULL
;
1793 //===========================================================================================================================
1795 //===========================================================================================================================
1797 DEBUG_LOCAL OSStatus
1798 HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
)
1800 struct sockaddr_in6 addr_6
;
1801 struct sockaddr_in addr_4
;
1802 int numAliases
= ALIASES_INITIAL_SIZE
;
1809 OSStatus err
= kNoErr
;
1812 check( self
->m_fp
);
1817 *hInfo
= (HostsFileInfo
*) malloc( sizeof( HostsFileInfo
) );
1818 require_action( *hInfo
, exit
, err
= kNoMemoryErr
);
1819 memset( *hInfo
, 0, sizeof( HostsFileInfo
) );
1823 line
= fgets( self
->m_buffer
+ idx
, self
->m_bufferSize
- idx
, self
->m_fp
);
1831 // If there's no eol and no eof, then we didn't get the whole line
1833 if ( !strchr( line
, '\n' ) && !feof( self
->m_fp
) )
1838 /* Try and allocate space for longer line */
1840 bufferSize
= self
->m_bufferSize
* 2;
1841 buffer
= (char*) realloc( self
->m_buffer
, bufferSize
);
1842 require_action( buffer
, exit
, err
= kNoMemoryErr
);
1843 self
->m_bufferSize
= bufferSize
;
1844 self
->m_buffer
= buffer
;
1845 idx
= (int) strlen( self
->m_buffer
);
1850 line
= self
->m_buffer
;
1858 // Get rid of either comments or eol characters
1860 if (( tok
= strpbrk(line
, "#\n")) != NULL
)
1865 // Make sure there is some whitespace on this line
1867 if (( tok
= strpbrk(line
, " \t")) == NULL
)
1872 // Create two strings, where p == the IP Address and tok is the name list
1876 while ( *tok
== ' ' || *tok
== '\t')
1881 // Now we have the name
1883 (*hInfo
)->m_host
.h_name
= (char*) malloc( strlen( tok
) + 1 );
1884 require_action( (*hInfo
)->m_host
.h_name
, exit
, err
= kNoMemoryErr
);
1885 strcpy( (*hInfo
)->m_host
.h_name
, tok
);
1887 // Now create the address (IPv6/IPv4)
1889 addr_6
.sin6_family
= family
= AF_INET6
;
1890 dwSize
= sizeof( addr_6
);
1892 if ( WSAStringToAddress( line
, AF_INET6
, NULL
, ( struct sockaddr
*) &addr_6
, &dwSize
) != 0 )
1894 addr_4
.sin_family
= family
= AF_INET
;
1895 dwSize
= sizeof( addr_4
);
1897 if (WSAStringToAddress( line
, AF_INET
, NULL
, ( struct sockaddr
*) &addr_4
, &dwSize
) != 0 )
1903 (*hInfo
)->m_host
.h_addr_list
= (char**) malloc( sizeof( char**) * 2 );
1904 require_action( (*hInfo
)->m_host
.h_addr_list
, exit
, err
= kNoMemoryErr
);
1906 if ( family
== AF_INET6
)
1908 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_6
.sin6_addr
);
1909 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
1910 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
1911 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_6
.sin6_addr
, sizeof( addr_6
.sin6_addr
) );
1916 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_4
.sin_addr
);
1917 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
1918 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
1919 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_4
.sin_addr
, sizeof( addr_4
.sin_addr
) );
1922 (*hInfo
)->m_host
.h_addr_list
[1] = NULL
;
1923 (*hInfo
)->m_host
.h_addrtype
= family
;
1925 // Now get the aliases
1927 if ((tok
= strpbrk(tok
, " \t")) != NULL
)
1934 (*hInfo
)->m_host
.h_aliases
= (char**) malloc( sizeof(char**) * numAliases
);
1935 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
1936 (*hInfo
)->m_host
.h_aliases
[0] = NULL
;
1938 while ( tok
&& *tok
)
1940 // Skip over the whitespace, waiting for the start of the next alias name
1942 if (*tok
== ' ' || *tok
== '\t')
1948 // Check to make sure we don't exhaust the alias buffer
1950 if ( i
>= ( numAliases
- 1 ) )
1952 numAliases
= numAliases
* 2;
1953 (*hInfo
)->m_host
.h_aliases
= (char**) realloc( (*hInfo
)->m_host
.h_aliases
, numAliases
* sizeof( char** ) );
1954 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
1957 (*hInfo
)->m_host
.h_aliases
[i
] = (char*) malloc( strlen( tok
) + 1 );
1958 require_action( (*hInfo
)->m_host
.h_aliases
[i
], exit
, err
= kNoMemoryErr
);
1960 strcpy( (*hInfo
)->m_host
.h_aliases
[i
], tok
);
1962 if (( tok
= strpbrk( tok
, " \t")) != NULL
)
1967 (*hInfo
)->m_host
.h_aliases
[++i
] = NULL
;
1975 if ( err
&& ( *hInfo
) )
1977 HostsFileInfoFree( *hInfo
);
1985 //===========================================================================================================================
1987 //===========================================================================================================================
1988 DEBUG_LOCAL
const char*
1989 GetNextLabel(const char *cstr
, char label
[64])
1992 while (*cstr
&& *cstr
!= '.') // While we have characters in the label...
1998 if (isdigit(cstr
[-1]) && isdigit(cstr
[0]) && isdigit(cstr
[1]))
2000 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
2001 int v1
= cstr
[ 0] - '0';
2002 int v2
= cstr
[ 1] - '0';
2003 int val
= v0
* 100 + v1
* 10 + v2
;
2004 if (val
<= 255) { c
= (char)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
2008 if (ptr
>= label
+64) return(NULL
);
2010 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
2016 #ifdef ENABLE_REVERSE_LOOKUP
2017 //===========================================================================================================================
2019 //===========================================================================================================================
2021 DEBUG_LOCAL OSStatus
2022 IsReverseLookup( LPCWSTR name
, size_t size
)
2025 OSStatus err
= kNoErr
;
2027 require_action_quiet( size
> sizeof_string( ".0.8.e.f.ip6.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2029 p
= name
+ ( size
- 1 );
2030 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
2032 if ( ( ( p
[ 0 ] != '.' ) ||
2033 ( ( p
[ 1 ] != '0' ) ) ||
2034 ( ( p
[ 2 ] != '.' ) ) ||
2035 ( ( p
[ 3 ] != '8' ) ) ||
2036 ( ( p
[ 4 ] != '.' ) ) ||
2037 ( ( p
[ 5 ] != 'E' ) && ( p
[ 5 ] != 'e' ) ) ||
2038 ( ( p
[ 6 ] != '.' ) ) ||
2039 ( ( p
[ 7 ] != 'F' ) && ( p
[ 7 ] != 'f' ) ) ||
2040 ( ( p
[ 8 ] != '.' ) ) ||
2041 ( ( p
[ 9 ] != 'I' ) && ( p
[ 9 ] != 'i' ) ) ||
2042 ( ( p
[ 10 ] != 'P' ) && ( p
[ 10 ] != 'p' ) ) ||
2043 ( ( p
[ 11 ] != '6' ) ) ||
2044 ( ( p
[ 12 ] != '.' ) ) ||
2045 ( ( p
[ 13 ] != 'A' ) && ( p
[ 13 ] != 'a' ) ) ||
2046 ( ( p
[ 14 ] != 'R' ) && ( p
[ 14 ] != 'r' ) ) ||
2047 ( ( p
[ 15 ] != 'P' ) && ( p
[ 15 ] != 'p' ) ) ||
2048 ( ( p
[ 16 ] != 'A' ) && ( p
[ 16 ] != 'a' ) ) ) )
2050 require_action_quiet( size
> sizeof_string( ".254.169.in-addr.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2052 p
= name
+ ( size
- 1 );
2053 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
2055 require_action_quiet( ( ( p
[ 0 ] == '.' ) &&
2056 ( ( p
[ 1 ] == '2' ) ) &&
2057 ( ( p
[ 2 ] == '5' ) ) &&
2058 ( ( p
[ 3 ] == '4' ) ) &&
2059 ( ( p
[ 4 ] == '.' ) ) &&
2060 ( ( p
[ 5 ] == '1' ) ) &&
2061 ( ( p
[ 6 ] == '6' ) ) &&
2062 ( ( p
[ 7 ] == '9' ) ) &&
2063 ( ( p
[ 8 ] == '.' ) ) &&
2064 ( ( p
[ 9 ] == 'I' ) || ( p
[ 9 ] == 'i' ) ) &&
2065 ( ( p
[ 10 ] == 'N' ) || ( p
[ 10 ] == 'n' ) ) &&
2066 ( ( p
[ 11 ] == '-' ) ) &&
2067 ( ( p
[ 12 ] == 'A' ) || ( p
[ 12 ] == 'a' ) ) &&
2068 ( ( p
[ 13 ] == 'D' ) || ( p
[ 13 ] == 'd' ) ) &&
2069 ( ( p
[ 14 ] == 'D' ) || ( p
[ 14 ] == 'd' ) ) &&
2070 ( ( p
[ 15 ] == 'R' ) || ( p
[ 15 ] == 'r' ) ) &&
2071 ( ( p
[ 16 ] == '.' ) ) &&
2072 ( ( p
[ 17 ] == 'A' ) || ( p
[ 17 ] == 'a' ) ) &&
2073 ( ( p
[ 18 ] == 'R' ) || ( p
[ 18 ] == 'r' ) ) &&
2074 ( ( p
[ 19 ] == 'P' ) || ( p
[ 19 ] == 'p' ) ) &&
2075 ( ( p
[ 20 ] == 'A' ) || ( p
[ 20 ] == 'a' ) ) ),
2076 exit
, err
= WSASERVICE_NOT_FOUND
);
2079 // It's a reverse lookup
2081 check( err
== kNoErr
);