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.10 2005/02/23 22:16:07 shersche
27 Unregister the NSP before registering to workaround an installer problem during upgrade installs
29 Revision 1.9 2005/02/01 01:45:55 shersche
30 Change mdnsNSP timeout to 2 seconds
32 Revision 1.8 2005/01/31 23:27:25 shersche
33 <rdar://problem/3936771> Don't try and resolve .local hostnames that are referenced in the hosts file
35 Revision 1.7 2005/01/28 23:50:13 shersche
36 <rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
39 Revision 1.6 2004/12/06 01:56:53 shersche
40 <rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
43 Revision 1.5 2004/07/13 21:24:28 rpantos
44 Fix for <rdar://problem/3701120>.
46 Revision 1.4 2004/07/09 18:03:33 shersche
47 removed extraneous DNSServiceQueryRecord call
49 Revision 1.3 2004/07/07 17:03:49 shersche
50 <rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
53 Revision 1.2 2004/06/24 19:18:07 shersche
55 Submitted by: herscher
57 Revision 1.1 2004/06/18 04:13:44 rpantos
60 Revision 1.2 2004/04/08 09:43:43 bradley
61 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
63 Revision 1.1 2004/01/30 03:00:33 bradley
64 mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
65 .local name lookups using Multicast DNS in all Windows apps.
73 #include "CommonServices.h"
74 #include "DebugServices.h"
82 #pragma mark == Structures ==
85 //===========================================================================================================================
87 //===========================================================================================================================
89 typedef struct Query
* QueryRef
;
90 typedef struct Query Query
;
96 WSAQUERYSETW
* querySet
;
100 HANDLE waitHandles
[ 2 ];
102 DNSServiceRef resolver
;
103 char name
[ kDNSServiceMaxDomainName
];
109 #define BUFFER_INITIAL_SIZE 4192
110 #define ALIASES_INITIAL_SIZE 5
112 typedef struct HostsFile
120 typedef struct HostsFileInfo
122 struct hostent m_host
;
123 struct HostsFileInfo
* m_next
;
128 #pragma mark == Prototypes ==
131 //===========================================================================================================================
133 //===========================================================================================================================
137 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
138 STDAPI
DllRegisterServer( void );
139 STDAPI
DllRegisterServer( void );
144 int WSPAPI
NSPCleanup( LPGUID inProviderID
);
146 DEBUG_LOCAL
int WSPAPI
147 NSPLookupServiceBegin(
149 LPWSAQUERYSETW inQuerySet
,
150 LPWSASERVICECLASSINFOW inServiceClassInfo
,
152 LPHANDLE outLookup
);
154 DEBUG_LOCAL
int WSPAPI
155 NSPLookupServiceNext(
158 LPDWORD ioBufferLength
,
159 LPWSAQUERYSETW outResults
);
161 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
);
163 DEBUG_LOCAL
int WSPAPI
166 LPWSASERVICECLASSINFOW inServiceClassInfo
,
167 LPWSAQUERYSETW inRegInfo
,
168 WSAESETSERVICEOP inOperation
,
171 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
);
172 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
);
173 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioBufSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
);
177 #define NSPLock() EnterCriticalSection( &gLock );
178 #define NSPUnlock() LeaveCriticalSection( &gLock );
180 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
);
181 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
);
182 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
);
184 DEBUG_LOCAL
void CALLBACK_COMPAT
187 DNSServiceFlags inFlags
,
188 uint32_t inInterfaceIndex
,
189 DNSServiceErrorType inErrorCode
,
193 uint16_t inRDataSize
,
194 const void * inRData
,
201 const WSAQUERYSETW
* inQuerySet
,
202 DWORD inQuerySetFlags
,
203 WSAQUERYSETW
** outQuerySet
,
209 const WSAQUERYSETW
* inQuerySet
,
210 DWORD inQuerySetFlags
,
211 WSAQUERYSETW
* outQuerySet
);
213 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
);
216 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
);
218 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
220 #define dlog_query_set( LEVEL, SET )
223 DEBUG_LOCAL BOOL
InHostsTable( const char * name
);
224 DEBUG_LOCAL BOOL
IsLocalName( HostsFileInfo
* node
);
225 DEBUG_LOCAL BOOL
IsSameName( HostsFileInfo
* node
, const char * name
);
226 DEBUG_LOCAL OSStatus
HostsFileOpen( HostsFile
** self
, const char * fname
);
227 DEBUG_LOCAL OSStatus
HostsFileClose( HostsFile
* self
);
228 DEBUG_LOCAL
void HostsFileInfoFree( HostsFileInfo
* info
);
229 DEBUG_LOCAL OSStatus
HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
);
233 #pragma mark == Globals ==
236 //===========================================================================================================================
238 //===========================================================================================================================
240 // {B600E6E9-553B-4a19-8696-335E5C896153}
241 DEBUG_LOCAL HINSTANCE gInstance
= NULL
;
242 DEBUG_LOCAL
wchar_t * gNSPName
= L
"mdnsNSP";
243 DEBUG_LOCAL GUID gNSPGUID
= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
244 DEBUG_LOCAL LONG gRefCount
= 0;
245 DEBUG_LOCAL CRITICAL_SECTION gLock
;
246 DEBUG_LOCAL
bool gLockInitialized
= false;
247 DEBUG_LOCAL
bool gDNSSDInitialized
= false;
248 DEBUG_LOCAL QueryRef gQueryList
= NULL
;
249 DEBUG_LOCAL HostsFileInfo
* gHostsFileInfo
= 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
, kDebugLevelInfo
);
271 dlog( kDebugLevelTrace
, "\n" );
272 dlog( kDebugLevelVerbose
, "%s: process attach\n", __ROUTINE__
);
275 case DLL_PROCESS_DETACH
:
276 HostsFileInfoFree( gHostsFileInfo
);
277 gHostsFileInfo
= NULL
;
278 dlog( kDebugLevelVerbose
, "%s: process detach\n", __ROUTINE__
);
281 case DLL_THREAD_ATTACH
:
282 dlog( kDebugLevelVerbose
, "%s: thread attach\n", __ROUTINE__
);
285 case DLL_THREAD_DETACH
:
286 dlog( kDebugLevelVerbose
, "%s: thread detach\n", __ROUTINE__
);
290 dlog( kDebugLevelNotice
, "%s: unknown reason code (%d)\n", __ROUTINE__
, inReason
);
297 //===========================================================================================================================
299 //===========================================================================================================================
301 STDAPI
DllRegisterServer( void )
304 WCHAR path
[ MAX_PATH
];
307 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
309 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
310 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
311 require_noerr( err
, exit
);
313 // Unregister before registering to workaround an installer
314 // problem during upgrade installs.
316 WSCUnInstallNameSpace( &gNSPGUID
);
318 err
= GetModuleFileNameW( gInstance
, path
, sizeof( path
) );
319 err
= translate_errno( err
!= 0, errno_compat(), kUnknownErr
);
320 require_noerr( err
, exit
);
322 err
= WSCInstallNameSpace( gNSPName
, path
, NS_DNS
, 1, &gNSPGUID
);
323 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
324 require_noerr( err
, exit
);
332 //===========================================================================================================================
333 // DllUnregisterServer
334 //===========================================================================================================================
336 STDAPI
DllUnregisterServer( void )
341 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
343 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
344 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
345 require_noerr( err
, exit
);
347 err
= WSCUnInstallNameSpace( &gNSPGUID
);
348 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
349 require_noerr( err
, exit
);
358 //===========================================================================================================================
361 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
362 //===========================================================================================================================
364 int WSPAPI
NSPStartup( LPGUID inProviderID
, LPNSP_ROUTINE outRoutines
)
368 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
369 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
371 // Only initialize if this is the first time NSPStartup is called.
373 if( InterlockedIncrement( &gRefCount
) != 1 )
379 // Initialize our internal state.
381 InitializeCriticalSection( &gLock
);
382 gLockInitialized
= true;
384 // Set the size to exclude NSPIoctl because we don't implement it.
386 outRoutines
->cbSize
= FIELD_OFFSET( NSP_ROUTINE
, NSPIoctl
);
387 outRoutines
->dwMajorVersion
= 4;
388 outRoutines
->dwMinorVersion
= 4;
389 outRoutines
->NSPCleanup
= NSPCleanup
;
390 outRoutines
->NSPLookupServiceBegin
= NSPLookupServiceBegin
;
391 outRoutines
->NSPLookupServiceNext
= NSPLookupServiceNext
;
392 outRoutines
->NSPLookupServiceEnd
= NSPLookupServiceEnd
;
393 outRoutines
->NSPSetService
= NSPSetService
;
394 outRoutines
->NSPInstallServiceClass
= NSPInstallServiceClass
;
395 outRoutines
->NSPRemoveServiceClass
= NSPRemoveServiceClass
;
396 outRoutines
->NSPGetServiceClassInfo
= NSPGetServiceClassInfo
;
401 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
402 if( err
!= NO_ERROR
)
404 NSPCleanup( inProviderID
);
405 SetLastError( (DWORD
) err
);
406 return( SOCKET_ERROR
);
411 //===========================================================================================================================
414 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
415 //===========================================================================================================================
417 int WSPAPI
NSPCleanup( LPGUID inProviderID
)
419 DEBUG_USE_ONLY( inProviderID
);
421 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
422 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
424 // Only initialize if this is the first time NSPStartup is called.
426 if( InterlockedDecrement( &gRefCount
) != 0 )
431 // Stop any outstanding queries.
433 if( gLockInitialized
)
439 check_string( gQueryList
->refCount
== 1, "NSPCleanup with outstanding queries!" );
440 QueryRelease( gQueryList
);
442 if( gLockInitialized
)
447 // Shut down DNS-SD and release our resources.
449 if( gDNSSDInitialized
)
451 gDNSSDInitialized
= false;
453 if( gLockInitialized
)
455 gLockInitialized
= false;
456 DeleteCriticalSection( &gLock
);
460 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
464 //===========================================================================================================================
465 // NSPLookupServiceBegin
467 // This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
468 // that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
469 // opposed to specifying the query parameters each time.
470 //===========================================================================================================================
472 DEBUG_LOCAL
int WSPAPI
473 NSPLookupServiceBegin(
475 LPWSAQUERYSETW inQuerySet
,
476 LPWSASERVICECLASSINFOW inServiceClassInfo
,
491 DEBUG_UNUSED( inProviderID
);
492 DEBUG_UNUSED( inServiceClassInfo
);
494 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
497 require_action( inQuerySet
, exit
, err
= WSAEINVAL
);
498 name
= inQuerySet
->lpszServiceInstanceName
;
499 require_action_quiet( name
, exit
, err
= WSAEINVAL
);
500 require_action( outLookup
, exit
, err
= WSAEINVAL
);
502 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__
, inFlags
, name
);
503 dlog_query_set( kDebugLevelVerbose
, inQuerySet
);
505 // Check if we can handle this type of request and if we support any of the protocols being requested.
506 // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
508 require_action_quiet( inFlags
& (LUP_RETURN_ADDR
|LUP_RETURN_BLOB
), exit
, err
= WSASERVICE_NOT_FOUND
);
510 type
= inQuerySet
->dwNameSpace
;
511 require_action_quiet( ( type
== NS_DNS
) || ( type
== NS_ALL
), exit
, err
= WSASERVICE_NOT_FOUND
);
513 n
= inQuerySet
->dwNumberOfProtocols
;
516 require_action( inQuerySet
->lpafpProtocols
, exit
, err
= WSAEINVAL
);
517 for( i
= 0; i
< n
; ++i
)
519 family
= inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
;
520 protocol
= inQuerySet
->lpafpProtocols
[ i
].iProtocol
;
521 if( ( family
== AF_INET
) && ( ( protocol
== IPPROTO_UDP
) || ( protocol
== IPPROTO_TCP
) ) )
526 require_action_quiet( i
< n
, exit
, err
= WSASERVICE_NOT_FOUND
);
529 // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
530 // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
531 // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
532 // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
533 // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
535 for( p
= name
; *p
; ++p
) {} // Find end of string
536 size
= (size_t)( p
- name
);
537 require_action_quiet( size
> sizeof_string( ".local" ), exit
, err
= WSASERVICE_NOT_FOUND
);
539 p
= name
+ ( size
- 1 );
540 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".local" ) ) : ( ( p
- sizeof_string( ".local" ) ) + 1 );
541 if ( ( ( p
[ 0 ] != '.' ) ||
542 ( ( p
[ 1 ] != 'L' ) && ( p
[ 1 ] != 'l' ) ) ||
543 ( ( p
[ 2 ] != 'O' ) && ( p
[ 2 ] != 'o' ) ) ||
544 ( ( p
[ 3 ] != 'C' ) && ( p
[ 3 ] != 'c' ) ) ||
545 ( ( p
[ 4 ] != 'A' ) && ( p
[ 4 ] != 'a' ) ) ||
546 ( ( p
[ 5 ] != 'L' ) && ( p
[ 5 ] != 'l' ) ) ) )
548 require_action_quiet( size
> sizeof_string( ".0.8.e.f.ip6.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
550 p
= name
+ ( size
- 1 );
551 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
553 if ( ( ( p
[ 0 ] != '.' ) ||
554 ( ( p
[ 1 ] != '0' ) ) ||
555 ( ( p
[ 2 ] != '.' ) ) ||
556 ( ( p
[ 3 ] != '8' ) ) ||
557 ( ( p
[ 4 ] != '.' ) ) ||
558 ( ( p
[ 5 ] != 'E' ) && ( p
[ 5 ] != 'e' ) ) ||
559 ( ( p
[ 6 ] != '.' ) ) ||
560 ( ( p
[ 7 ] != 'F' ) && ( p
[ 7 ] != 'f' ) ) ||
561 ( ( p
[ 8 ] != '.' ) ) ||
562 ( ( p
[ 9 ] != 'I' ) && ( p
[ 9 ] != 'i' ) ) ||
563 ( ( p
[ 10 ] != 'P' ) && ( p
[ 10 ] != 'p' ) ) ||
564 ( ( p
[ 11 ] != '6' ) ) ||
565 ( ( p
[ 12 ] != '.' ) ) ||
566 ( ( p
[ 13 ] != 'A' ) && ( p
[ 13 ] != 'a' ) ) ||
567 ( ( p
[ 14 ] != 'R' ) && ( p
[ 14 ] != 'r' ) ) ||
568 ( ( p
[ 15 ] != 'P' ) && ( p
[ 15 ] != 'p' ) ) ||
569 ( ( p
[ 16 ] != 'A' ) && ( p
[ 16 ] != 'a' ) ) ) )
571 require_action_quiet( size
> sizeof_string( ".254.169.in-addr.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
573 p
= name
+ ( size
- 1 );
574 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
576 require_action_quiet( ( ( p
[ 0 ] == '.' ) &&
577 ( ( p
[ 1 ] == '2' ) ) &&
578 ( ( p
[ 2 ] == '5' ) ) &&
579 ( ( p
[ 3 ] == '4' ) ) &&
580 ( ( p
[ 4 ] == '.' ) ) &&
581 ( ( p
[ 5 ] == '1' ) ) &&
582 ( ( p
[ 6 ] == '6' ) ) &&
583 ( ( p
[ 7 ] == '9' ) ) &&
584 ( ( p
[ 8 ] == '.' ) ) &&
585 ( ( p
[ 9 ] == 'I' ) || ( p
[ 9 ] == 'i' ) ) &&
586 ( ( p
[ 10 ] == 'N' ) || ( p
[ 10 ] == 'n' ) ) &&
587 ( ( p
[ 11 ] == '-' ) ) &&
588 ( ( p
[ 12 ] == 'A' ) || ( p
[ 12 ] == 'a' ) ) &&
589 ( ( p
[ 13 ] == 'D' ) || ( p
[ 13 ] == 'd' ) ) &&
590 ( ( p
[ 14 ] == 'D' ) || ( p
[ 14 ] == 'd' ) ) &&
591 ( ( p
[ 15 ] == 'R' ) || ( p
[ 15 ] == 'r' ) ) &&
592 ( ( p
[ 16 ] == '.' ) ) &&
593 ( ( p
[ 17 ] == 'A' ) || ( p
[ 17 ] == 'a' ) ) &&
594 ( ( p
[ 18 ] == 'R' ) || ( p
[ 18 ] == 'r' ) ) &&
595 ( ( p
[ 19 ] == 'P' ) || ( p
[ 19 ] == 'p' ) ) &&
596 ( ( p
[ 20 ] == 'A' ) || ( p
[ 20 ] == 'a' ) ) ),
597 exit
, err
= WSASERVICE_NOT_FOUND
);
602 // <rdar://problem/3936771>
604 // Check to see if the name of this host is in the hosts table. If so,
605 // don't try and resolve it
607 char translated
[ kDNSServiceMaxDomainName
];
610 n
= WideCharToMultiByte( CP_UTF8
, 0, name
, -1, translated
, sizeof( translated
), NULL
, NULL
);
611 require_action( n
> 0, exit
, err
= WSASERVICE_NOT_FOUND
);
612 require_action( InHostsTable( translated
) == FALSE
, exit
, err
= WSASERVICE_NOT_FOUND
);
615 // 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 if( !gDNSSDInitialized
)
620 gDNSSDInitialized
= true;
623 err
= QueryCreate( inQuerySet
, inFlags
, &obj
);
625 require_noerr( err
, exit
);
627 *outLookup
= (HANDLE
) obj
;
630 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
631 if( err
!= NO_ERROR
)
633 SetLastError( (DWORD
) err
);
634 return( SOCKET_ERROR
);
639 //===========================================================================================================================
640 // NSPLookupServiceNext
642 // This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
643 // query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
644 // in the lpqsResults parameter.
645 //===========================================================================================================================
647 DEBUG_LOCAL
int WSPAPI
648 NSPLookupServiceNext(
652 LPWSAQUERYSETW outResults
)
659 DEBUG_USE_ONLY( inFlags
);
661 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
665 err
= QueryRetain( (QueryRef
) inLookup
);
666 require_noerr( err
, exit
);
667 obj
= (QueryRef
) inLookup
;
668 require_action( ioSize
, exit
, err
= WSAEINVAL
);
669 require_action( outResults
, exit
, err
= WSAEINVAL
);
671 dlog( kDebugLevelTrace
, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__
, inLookup
, inFlags
, *ioSize
);
673 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
676 waitResult
= WaitForMultipleObjects( obj
->waitCount
, obj
->waitHandles
, FALSE
, 2 * 1000 );
678 require_action_quiet( waitResult
!= ( WAIT_OBJECT_0
+ 1 ), exit
, err
= WSA_E_CANCELLED
);
679 err
= translate_errno( waitResult
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), WSASERVICE_NOT_FOUND
);
680 require_noerr_quiet( err
, exit
);
681 DNSServiceProcessResult(obj
->resolver
);
682 require_action_quiet( obj
->addrValid
, exit
, err
= WSA_E_NO_MORE
);
684 // Copy the externalized query results to the callers buffer (if it fits).
686 size
= QueryCopyQuerySetSize( obj
, obj
->querySet
, obj
->querySetFlags
);
687 require_action( size
<= (size_t) *ioSize
, exit
, err
= WSAEFAULT
);
689 QueryCopyQuerySetTo( obj
, obj
->querySet
, obj
->querySetFlags
, outResults
);
690 outResults
->dwOutputFlags
= RESULT_IS_ADDED
;
691 obj
->addrValid
= false;
699 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
700 if( err
!= NO_ERROR
)
702 SetLastError( (DWORD
) err
);
703 return( SOCKET_ERROR
);
708 //===========================================================================================================================
709 // NSPLookupServiceEnd
711 // This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
712 // indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
713 // allocated resources associated with the query.
714 //===========================================================================================================================
716 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
)
720 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
722 dlog( kDebugLevelTrace
, "%s (lookup=%#p)\n", __ROUTINE__
, inLookup
);
725 err
= QueryRelease( (QueryRef
) inLookup
);
727 require_noerr( err
, exit
);
730 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
731 if( err
!= NO_ERROR
)
733 SetLastError( (DWORD
) err
);
734 return( SOCKET_ERROR
);
739 //===========================================================================================================================
742 // This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
743 // deregister an instance of a server with our service. For registration, the user needs to associate the server with a
744 // service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
745 // contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
746 //===========================================================================================================================
748 DEBUG_LOCAL
int WSPAPI
751 LPWSASERVICECLASSINFOW inServiceClassInfo
,
752 LPWSAQUERYSETW inRegInfo
,
753 WSAESETSERVICEOP inOperation
,
756 DEBUG_UNUSED( inProviderID
);
757 DEBUG_UNUSED( inServiceClassInfo
);
758 DEBUG_UNUSED( inRegInfo
);
759 DEBUG_UNUSED( inOperation
);
760 DEBUG_UNUSED( inFlags
);
762 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
763 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
765 // We don't allow services to be registered so always return an error.
767 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
771 //===========================================================================================================================
772 // NSPInstallServiceClass
774 // This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
775 // is used to define certain characteristics for a group of services. After a service class is registered, an actual
776 // instance of a server may be registered.
777 //===========================================================================================================================
779 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
)
781 DEBUG_UNUSED( inProviderID
);
782 DEBUG_UNUSED( inServiceClassInfo
);
784 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
785 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
787 // We don't allow service classes to be installed so always return an error.
789 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
790 return( WSA_INVALID_PARAMETER
);
793 //===========================================================================================================================
794 // NSPRemoveServiceClass
796 // This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
797 // class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
799 //===========================================================================================================================
801 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
)
803 DEBUG_UNUSED( inProviderID
);
804 DEBUG_UNUSED( inServiceClassID
);
806 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
807 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
809 // We don't allow service classes to be installed so always return an error.
811 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
812 return( WSATYPE_NOT_FOUND
);
815 //===========================================================================================================================
816 // NSPGetServiceClassInfo
818 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
819 // a given service class.
820 //===========================================================================================================================
822 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
)
824 DEBUG_UNUSED( inProviderID
);
825 DEBUG_UNUSED( ioSize
);
826 DEBUG_UNUSED( ioServiceClassInfo
);
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( WSATYPE_NOT_FOUND
);
841 //===========================================================================================================================
844 // Warning: Assumes the NSP lock is held.
845 //===========================================================================================================================
847 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
)
851 char name
[ kDNSServiceMaxDomainName
];
857 check( inQuerySet
->lpszServiceInstanceName
);
860 // Convert the wchar_t name to UTF-8.
862 n
= WideCharToMultiByte( CP_UTF8
, 0, inQuerySet
->lpszServiceInstanceName
, -1, name
, sizeof( name
), NULL
, NULL
);
863 err
= translate_errno( n
> 0, (OSStatus
) GetLastError(), WSAEINVAL
);
864 require_noerr( err
, exit
);
866 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
868 obj
= (QueryRef
) calloc( 1, sizeof( *obj
) );
869 require_action( obj
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
873 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
) {} // Find the end of the list.
876 // Set up events to signal when data is ready and when cancelling.
878 obj
->dataEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
879 require_action( obj
->dataEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
881 obj
->cancelEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
882 require_action( obj
->cancelEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
886 err
= DNSServiceQueryRecord( &obj
->resolver
, 0, 0, name
, kDNSServiceType_A
, kDNSServiceClass_IN
,
887 QueryRecordCallback
, obj
);
888 require_noerr( err
, exit
);
890 // Attach the socket to the event
892 WSAEventSelect(DNSServiceRefSockFD(obj
->resolver
), obj
->dataEvent
, FD_READ
|FD_CLOSE
);
895 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->dataEvent
;
896 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->cancelEvent
;
897 check( obj
->waitCount
== sizeof_array( obj
->waitHandles
) );
899 // Copy the QuerySet so it can be returned later.
901 obj
->querySetFlags
= inQuerySetFlags
;
902 inQuerySetFlags
= ( inQuerySetFlags
& ~( LUP_RETURN_ADDR
| LUP_RETURN_BLOB
) ) | LUP_RETURN_NAME
;
903 err
= QueryCopyQuerySet( obj
, inQuerySet
, inQuerySetFlags
, &obj
->querySet
, &obj
->querySetSize
);
904 require_noerr( err
, exit
);
920 //===========================================================================================================================
923 // Warning: Assumes the NSP lock is held.
924 //===========================================================================================================================
926 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
)
931 for( obj
= gQueryList
; obj
; obj
= obj
->next
)
938 require_action( obj
, exit
, err
= WSA_INVALID_HANDLE
);
947 //===========================================================================================================================
950 // Warning: Assumes the NSP lock is held.
951 //===========================================================================================================================
953 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
)
959 // Find the item in the list.
961 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
)
968 require_action( *p
, exit
, err
= WSA_INVALID_HANDLE
);
970 // Signal a cancel to unblock any threads waiting for results.
972 if( inRef
->cancelEvent
)
974 ok
= SetEvent( inRef
->cancelEvent
);
975 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
980 if( inRef
->resolver
)
982 DNSServiceRefDeallocate( inRef
->resolver
);
983 inRef
->resolver
= NULL
;
986 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
988 if( --inRef
->refCount
!= 0 )
995 // Release resources.
997 if( inRef
->cancelEvent
)
999 ok
= CloseHandle( inRef
->cancelEvent
);
1000 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1002 if( inRef
->dataEvent
)
1004 ok
= CloseHandle( inRef
->dataEvent
);
1005 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1007 if( inRef
->querySet
)
1009 free( inRef
->querySet
);
1018 //===========================================================================================================================
1019 // QueryRecordCallback
1020 //===========================================================================================================================
1022 DEBUG_LOCAL
void CALLBACK_COMPAT
1023 QueryRecordCallback(
1024 DNSServiceRef inRef
,
1025 DNSServiceFlags inFlags
,
1026 uint32_t inInterfaceIndex
,
1027 DNSServiceErrorType inErrorCode
,
1028 const char * inName
,
1031 uint16_t inRDataSize
,
1032 const void * inRData
,
1041 DEBUG_UNUSED( inFlags
);
1042 DEBUG_UNUSED( inInterfaceIndex
);
1043 DEBUG_UNUSED( inTTL
);
1046 obj
= (QueryRef
) inContext
;
1048 require_noerr( inErrorCode
, exit
);
1049 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1050 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1051 require( inRRType
== kDNSServiceType_A
, exit
);
1052 require( inRDataSize
== 4, exit
);
1054 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1055 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1057 // Copy the name if needed.
1059 if( obj
->name
[ 0 ] == '\0' )
1063 while( *src
!= '\0' )
1068 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1069 check( obj
->nameSize
< sizeof( obj
->name
) );
1074 memcpy( &obj
->addr
, inRData
, inRDataSize
);
1075 obj
->addrValid
= true;
1077 // Signal that a result is ready.
1079 check( obj
->dataEvent
);
1080 ok
= SetEvent( obj
->dataEvent
);
1081 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1083 // Stop the resolver after the first response.
1085 DNSServiceRefDeallocate( inRef
);
1086 obj
->resolver
= NULL
;
1096 //===========================================================================================================================
1097 // QueryCopyQuerySet
1099 // Warning: Assumes the NSP lock is held.
1100 //===========================================================================================================================
1102 DEBUG_LOCAL OSStatus
1105 const WSAQUERYSETW
* inQuerySet
,
1106 DWORD inQuerySetFlags
,
1107 WSAQUERYSETW
** outQuerySet
,
1114 check( inQuerySet
);
1115 check( outQuerySet
);
1117 size
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1118 qs
= (WSAQUERYSETW
*) calloc( 1, size
);
1119 require_action( qs
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1121 QueryCopyQuerySetTo( inRef
, inQuerySet
, inQuerySetFlags
, qs
);
1139 //===========================================================================================================================
1140 // QueryCopyQuerySetTo
1142 // Warning: Assumes the NSP lock is held.
1143 //===========================================================================================================================
1146 QueryCopyQuerySetTo(
1148 const WSAQUERYSETW
* inQuerySet
,
1149 DWORD inQuerySetFlags
,
1150 WSAQUERYSETW
* outQuerySet
)
1161 debugSize
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1164 check( inQuerySet
);
1165 check( outQuerySet
);
1167 dst
= (uint8_t *) outQuerySet
;
1169 // Copy the static portion of the results.
1171 *outQuerySet
= *inQuerySet
;
1172 dst
+= sizeof( *inQuerySet
);
1174 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1176 s
= inQuerySet
->lpszServiceInstanceName
;
1179 outQuerySet
->lpszServiceInstanceName
= (LPWSTR
) dst
;
1181 while( ( *q
++ = *s
++ ) != 0 ) {}
1182 dst
= (uint8_t *) q
;
1187 outQuerySet
->lpszServiceInstanceName
= NULL
;
1190 if( inQuerySet
->lpServiceClassId
)
1192 outQuerySet
->lpServiceClassId
= (LPGUID
) dst
;
1193 *outQuerySet
->lpServiceClassId
= *inQuerySet
->lpServiceClassId
;
1194 dst
+= sizeof( *inQuerySet
->lpServiceClassId
);
1197 if( inQuerySet
->lpVersion
)
1199 outQuerySet
->lpVersion
= (LPWSAVERSION
) dst
;
1200 *outQuerySet
->lpVersion
= *inQuerySet
->lpVersion
;
1201 dst
+= sizeof( *inQuerySet
->lpVersion
);
1204 s
= inQuerySet
->lpszComment
;
1207 outQuerySet
->lpszComment
= (LPWSTR
) dst
;
1209 while( ( *q
++ = *s
++ ) != 0 ) {}
1210 dst
= (uint8_t *) q
;
1213 if( inQuerySet
->lpNSProviderId
)
1215 outQuerySet
->lpNSProviderId
= (LPGUID
) dst
;
1216 *outQuerySet
->lpNSProviderId
= *inQuerySet
->lpNSProviderId
;
1217 dst
+= sizeof( *inQuerySet
->lpNSProviderId
);
1220 s
= inQuerySet
->lpszContext
;
1223 outQuerySet
->lpszContext
= (LPWSTR
) dst
;
1225 while( ( *q
++ = *s
++ ) != 0 ) {}
1226 dst
= (uint8_t *) q
;
1229 n
= inQuerySet
->dwNumberOfProtocols
;
1232 check( inQuerySet
->lpafpProtocols
);
1234 outQuerySet
->lpafpProtocols
= (LPAFPROTOCOLS
) dst
;
1235 for( i
= 0; i
< n
; ++i
)
1237 outQuerySet
->lpafpProtocols
[ i
] = inQuerySet
->lpafpProtocols
[ i
];
1238 dst
+= sizeof( *inQuerySet
->lpafpProtocols
);
1242 s
= inQuerySet
->lpszQueryString
;
1245 outQuerySet
->lpszQueryString
= (LPWSTR
) dst
;
1247 while( ( *q
++ = *s
++ ) != 0 ) {}
1248 dst
= (uint8_t *) q
;
1251 // Copy the address(es).
1253 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addrValid
)
1255 struct sockaddr_in
* addr
;
1257 outQuerySet
->dwNumberOfCsAddrs
= 1;
1258 outQuerySet
->lpcsaBuffer
= (LPCSADDR_INFO
) dst
;
1259 dst
+= sizeof( *outQuerySet
->lpcsaBuffer
);
1261 outQuerySet
->lpcsaBuffer
[ 0 ].LocalAddr
.lpSockaddr
= NULL
;
1262 outQuerySet
->lpcsaBuffer
[ 0 ].LocalAddr
.iSockaddrLength
= 0;
1264 outQuerySet
->lpcsaBuffer
[ 0 ].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1265 outQuerySet
->lpcsaBuffer
[ 0 ].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in
);
1267 addr
= (struct sockaddr_in
*) dst
;
1268 memset( addr
, 0, sizeof( *addr
) );
1269 addr
->sin_family
= AF_INET
;
1270 memcpy( &addr
->sin_addr
, &inRef
->addr
, 4 );
1271 dst
+= sizeof( *addr
);
1273 outQuerySet
->lpcsaBuffer
[ 0 ].iSocketType
= AF_INET
; // Emulate Tcpip NSP
1274 outQuerySet
->lpcsaBuffer
[ 0 ].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1278 outQuerySet
->dwNumberOfCsAddrs
= 0;
1279 outQuerySet
->lpcsaBuffer
= NULL
;
1282 // Copy the hostent blob.
1284 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addrValid
)
1287 struct hostent
* he
;
1290 outQuerySet
->lpBlob
= (LPBLOB
) dst
;
1291 dst
+= sizeof( *outQuerySet
->lpBlob
);
1294 he
= (struct hostent
*) dst
;
1295 dst
+= sizeof( *he
);
1297 he
->h_name
= (char *)( dst
- base
);
1298 memcpy( dst
, inRef
->name
, inRef
->nameSize
+ 1 );
1299 dst
+= ( inRef
->nameSize
+ 1 );
1301 he
->h_aliases
= (char **)( dst
- base
);
1302 p
= (uintptr_t *) dst
;
1304 dst
= (uint8_t *) p
;
1306 he
->h_addrtype
= AF_INET
;
1309 he
->h_addr_list
= (char **)( dst
- base
);
1310 p
= (uintptr_t *) dst
;
1311 dst
+= ( 2 * sizeof( *p
) );
1312 *p
++ = (uintptr_t)( dst
- base
);
1314 p
= (uintptr_t *) dst
;
1315 *p
++ = (uintptr_t) inRef
->addr
;
1316 dst
= (uint8_t *) p
;
1318 outQuerySet
->lpBlob
->cbSize
= (ULONG
)( dst
- base
);
1319 outQuerySet
->lpBlob
->pBlobData
= (BYTE
*) base
;
1321 dlog_query_set( kDebugLevelVerbose
, outQuerySet
);
1323 check( (size_t)( dst
- ( (uint8_t *) outQuerySet
) ) == debugSize
);
1326 //===========================================================================================================================
1327 // QueryCopyQuerySetSize
1329 // Warning: Assumes the NSP lock is held.
1330 //===========================================================================================================================
1332 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
)
1339 check( inQuerySet
);
1341 // Calculate the size of the static portion of the results.
1343 size
= sizeof( *inQuerySet
);
1345 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1347 s
= inQuerySet
->lpszServiceInstanceName
;
1350 for( p
= s
; *p
; ++p
) {}
1351 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1355 if( inQuerySet
->lpServiceClassId
)
1357 size
+= sizeof( *inQuerySet
->lpServiceClassId
);
1360 if( inQuerySet
->lpVersion
)
1362 size
+= sizeof( *inQuerySet
->lpVersion
);
1365 s
= inQuerySet
->lpszComment
;
1368 for( p
= s
; *p
; ++p
) {}
1369 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1372 if( inQuerySet
->lpNSProviderId
)
1374 size
+= sizeof( *inQuerySet
->lpNSProviderId
);
1377 s
= inQuerySet
->lpszContext
;
1380 for( p
= s
; *p
; ++p
) {}
1381 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1384 size
+= ( inQuerySet
->dwNumberOfProtocols
* sizeof( *inQuerySet
->lpafpProtocols
) );
1386 s
= inQuerySet
->lpszQueryString
;
1389 for( p
= s
; *p
; ++p
) {}
1390 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1393 // Calculate the size of the address(es).
1395 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addrValid
)
1397 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1398 size
+= sizeof( struct sockaddr_in
);
1401 // Calculate the size of the hostent blob.
1403 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addrValid
)
1405 size
+= sizeof( *inQuerySet
->lpBlob
); // Blob ptr/size structure
1406 size
+= sizeof( struct hostent
); // Old-style hostent structure
1407 size
+= ( inRef
->nameSize
+ 1 ); // Name and null terminator
1408 size
+= 4; // Alias list terminator (0 offset)
1409 size
+= 4; // Offset to address.
1410 size
+= 4; // Address list terminator (0 offset)
1411 size
+= 4; // IPv4 address
1421 //===========================================================================================================================
1422 // DebugDumpQuerySet
1423 //===========================================================================================================================
1425 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1426 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1428 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1429 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1431 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1433 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
)
1437 check( inQuerySet
);
1439 // Fixed portion of the QuerySet.
1441 dlog( inLevel
, "QuerySet:\n" );
1442 dlog( inLevel
, " dwSize: %d (expected %d)\n", inQuerySet
->dwSize
, sizeof( *inQuerySet
) );
1443 if( inQuerySet
->lpszServiceInstanceName
)
1445 dlog( inLevel
, " lpszServiceInstanceName: %S\n", inQuerySet
->lpszServiceInstanceName
);
1449 dlog( inLevel
, " lpszServiceInstanceName: <null>\n" );
1451 if( inQuerySet
->lpServiceClassId
)
1453 dlog( inLevel
, " lpServiceClassId: %U\n", inQuerySet
->lpServiceClassId
);
1457 dlog( inLevel
, " lpServiceClassId: <null>\n" );
1459 if( inQuerySet
->lpVersion
)
1461 dlog( inLevel
, " lpVersion:\n" );
1462 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->dwVersion
);
1463 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->ecHow
);
1467 dlog( inLevel
, " lpVersion: <null>\n" );
1469 if( inQuerySet
->lpszComment
)
1471 dlog( inLevel
, " lpszComment: %S\n", inQuerySet
->lpszComment
);
1475 dlog( inLevel
, " lpszComment: <null>\n" );
1477 dlog( inLevel
, " dwNameSpace: %d %s\n", inQuerySet
->dwNameSpace
,
1478 DebugNameSpaceToString( inQuerySet
->dwNameSpace
) );
1479 if( inQuerySet
->lpNSProviderId
)
1481 dlog( inLevel
, " lpNSProviderId: %U\n", inQuerySet
->lpNSProviderId
);
1485 dlog( inLevel
, " lpNSProviderId: <null>\n" );
1487 if( inQuerySet
->lpszContext
)
1489 dlog( inLevel
, " lpszContext: %S\n", inQuerySet
->lpszContext
);
1493 dlog( inLevel
, " lpszContext: <null>\n" );
1495 dlog( inLevel
, " dwNumberOfProtocols: %d\n", inQuerySet
->dwNumberOfProtocols
);
1496 dlog( inLevel
, " lpafpProtocols: %s\n", inQuerySet
->lpafpProtocols
? "" : "<null>" );
1497 for( i
= 0; i
< inQuerySet
->dwNumberOfProtocols
; ++i
)
1501 dlog( inLevel
, "\n" );
1503 dlog( inLevel
, " iAddressFamily: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
,
1504 DebugSocketFamilyToString( inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
) );
1505 dlog( inLevel
, " iProtocol: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iProtocol
,
1506 DebugSocketProtocolToString( inQuerySet
->lpafpProtocols
[ i
].iProtocol
) );
1508 if( inQuerySet
->lpszQueryString
)
1510 dlog( inLevel
, " lpszQueryString: %S\n", inQuerySet
->lpszQueryString
);
1514 dlog( inLevel
, " lpszQueryString: <null>\n" );
1516 dlog( inLevel
, " dwNumberOfCsAddrs: %d\n", inQuerySet
->dwNumberOfCsAddrs
);
1517 dlog( inLevel
, " lpcsaBuffer: %s\n", inQuerySet
->lpcsaBuffer
? "" : "<null>" );
1518 for( i
= 0; i
< inQuerySet
->dwNumberOfCsAddrs
; ++i
)
1522 dlog( inLevel
, "\n" );
1524 if( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
&&
1525 ( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.iSockaddrLength
> 0 ) )
1527 dlog( inLevel
, " LocalAddr: %##a\n",
1528 inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
);
1532 dlog( inLevel
, " LocalAddr: <null/empty>\n" );
1534 if( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
&&
1535 ( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.iSockaddrLength
> 0 ) )
1537 dlog( inLevel
, " RemoteAddr: %##a\n",
1538 inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
);
1542 dlog( inLevel
, " RemoteAddr: <null/empty>\n" );
1544 dlog( inLevel
, " iSocketType: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iSocketType
);
1545 dlog( inLevel
, " iProtocol: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iProtocol
);
1547 dlog( inLevel
, " dwOutputFlags: %d\n", inQuerySet
->dwOutputFlags
);
1549 // Blob portion of the QuerySet.
1551 if( inQuerySet
->lpBlob
)
1553 dlog( inLevel
, " lpBlob:\n" );
1554 dlog( inLevel
, " cbSize: %ld\n", inQuerySet
->lpBlob
->cbSize
);
1555 dlog( inLevel
, " pBlobData: %#p\n", inQuerySet
->lpBlob
->pBlobData
);
1556 dloghex( inLevel
, 12, NULL
, 0, 0, NULL
, 0,
1557 inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->cbSize
,
1558 kDebugFlagsNone
, NULL
, 0 );
1562 dlog( inLevel
, " lpBlob: <null>\n" );
1568 //===========================================================================================================================
1570 //===========================================================================================================================
1573 InHostsTable( const char * name
)
1575 HostsFileInfo
* node
;
1581 if ( gHostsFileInfo
== NULL
)
1583 TCHAR systemDirectory
[MAX_PATH
];
1584 TCHAR hFileName
[MAX_PATH
];
1587 GetSystemDirectory( systemDirectory
, sizeof( systemDirectory
) );
1588 sprintf( hFileName
, "%s\\drivers\\etc\\hosts", systemDirectory
);
1589 err
= HostsFileOpen( &hFile
, hFileName
);
1590 require_noerr( err
, exit
);
1592 while ( HostsFileNext( hFile
, &node
) == 0 )
1594 if ( IsLocalName( node
) )
1596 node
->m_next
= gHostsFileInfo
;
1597 gHostsFileInfo
= node
;
1601 HostsFileInfoFree( node
);
1605 HostsFileClose( hFile
);
1608 for ( node
= gHostsFileInfo
; node
; node
= node
->m_next
)
1610 if ( IsSameName( node
, name
) )
1623 //===========================================================================================================================
1625 //===========================================================================================================================
1628 IsLocalName( HostsFileInfo
* node
)
1634 if ( strstr( node
->m_host
.h_name
, ".local" ) == NULL
)
1638 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1640 if ( strstr( node
->m_host
.h_aliases
[i
], ".local" ) )
1655 //===========================================================================================================================
1657 //===========================================================================================================================
1660 IsSameName( HostsFileInfo
* node
, const char * name
)
1667 if ( strcmp( node
->m_host
.h_name
, name
) != 0 )
1671 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1673 if ( strcmp( node
->m_host
.h_aliases
[i
], name
) == 0 )
1688 //===========================================================================================================================
1690 //===========================================================================================================================
1692 DEBUG_LOCAL OSStatus
1693 HostsFileOpen( HostsFile
** self
, const char * fname
)
1695 OSStatus err
= kNoErr
;
1697 *self
= (HostsFile
*) malloc( sizeof( HostsFile
) );
1698 require_action( *self
, exit
, err
= kNoMemoryErr
);
1699 memset( *self
, 0, sizeof( HostsFile
) );
1701 (*self
)->m_bufferSize
= BUFFER_INITIAL_SIZE
;
1702 (*self
)->m_buffer
= (char*) malloc( (*self
)->m_bufferSize
);
1703 require_action( (*self
)->m_buffer
, exit
, err
= kNoMemoryErr
);
1707 (*self
)->m_fp
= fopen( fname
, "r" );
1708 require_action( (*self
)->m_fp
, exit
, err
= kUnknownErr
);
1714 HostsFileClose( *self
);
1722 //===========================================================================================================================
1724 //===========================================================================================================================
1726 DEBUG_LOCAL OSStatus
1727 HostsFileClose( HostsFile
* self
)
1731 if ( self
->m_buffer
)
1733 free( self
->m_buffer
);
1734 self
->m_buffer
= NULL
;
1739 fclose( self
->m_fp
);
1749 //===========================================================================================================================
1750 // HostsFileInfoFree
1751 //===========================================================================================================================
1754 HostsFileInfoFree( HostsFileInfo
* info
)
1758 HostsFileInfo
* next
= info
->m_next
;
1760 if ( info
->m_host
.h_addr_list
)
1762 if ( info
->m_host
.h_addr_list
[0] )
1764 free( info
->m_host
.h_addr_list
[0] );
1765 info
->m_host
.h_addr_list
[0] = NULL
;
1768 free( info
->m_host
.h_addr_list
);
1769 info
->m_host
.h_addr_list
= NULL
;
1772 if ( info
->m_host
.h_aliases
)
1776 for ( i
= 0; info
->m_host
.h_aliases
[i
]; i
++ )
1778 free( info
->m_host
.h_aliases
[i
] );
1781 free( info
->m_host
.h_aliases
);
1784 if ( info
->m_host
.h_name
)
1786 free( info
->m_host
.h_name
);
1787 info
->m_host
.h_name
= NULL
;
1797 //===========================================================================================================================
1799 //===========================================================================================================================
1801 DEBUG_LOCAL OSStatus
1802 HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
)
1804 struct sockaddr_in6 addr_6
;
1805 struct sockaddr_in addr_4
;
1806 int numAliases
= ALIASES_INITIAL_SIZE
;
1813 OSStatus err
= kNoErr
;
1816 check( self
->m_fp
);
1821 *hInfo
= (HostsFileInfo
*) malloc( sizeof( HostsFileInfo
) );
1822 require_action( *hInfo
, exit
, err
= kNoMemoryErr
);
1823 memset( *hInfo
, 0, sizeof( HostsFileInfo
) );
1827 line
= fgets( self
->m_buffer
+ idx
, self
->m_bufferSize
- idx
, self
->m_fp
);
1835 // If there's no eol and no eof, then we didn't get the whole line
1837 if ( !strchr( line
, '\n' ) && !feof( self
->m_fp
) )
1842 /* Try and allocate space for longer line */
1844 bufferSize
= self
->m_bufferSize
* 2;
1845 buffer
= (char*) realloc( self
->m_buffer
, bufferSize
);
1846 require_action( buffer
, exit
, err
= kNoMemoryErr
);
1847 self
->m_bufferSize
= bufferSize
;
1848 self
->m_buffer
= buffer
;
1849 idx
= (int) strlen( self
->m_buffer
);
1854 line
= self
->m_buffer
;
1862 // Get rid of either comments or eol characters
1864 if (( tok
= strpbrk(line
, "#\n")) != NULL
)
1869 // Make sure there is some whitespace on this line
1871 if (( tok
= strpbrk(line
, " \t")) == NULL
)
1876 // Create two strings, where p == the IP Address and tok is the name list
1880 while ( *tok
== ' ' || *tok
== '\t')
1885 // Now we have the name
1887 (*hInfo
)->m_host
.h_name
= (char*) malloc( strlen( tok
) + 1 );
1888 require_action( (*hInfo
)->m_host
.h_name
, exit
, err
= kNoMemoryErr
);
1889 strcpy( (*hInfo
)->m_host
.h_name
, tok
);
1891 // Now create the address (IPv6/IPv4)
1893 addr_6
.sin6_family
= family
= AF_INET6
;
1894 dwSize
= sizeof( addr_6
);
1896 if ( WSAStringToAddress( line
, AF_INET6
, NULL
, ( struct sockaddr
*) &addr_6
, &dwSize
) != 0 )
1898 addr_4
.sin_family
= family
= AF_INET
;
1899 dwSize
= sizeof( addr_4
);
1901 if (WSAStringToAddress( line
, AF_INET
, NULL
, ( struct sockaddr
*) &addr_4
, &dwSize
) != 0 )
1907 (*hInfo
)->m_host
.h_addr_list
= (char**) malloc( sizeof( char**) * 2 );
1908 require_action( (*hInfo
)->m_host
.h_addr_list
, exit
, err
= kNoMemoryErr
);
1910 if ( family
== AF_INET6
)
1912 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_6
.sin6_addr
);
1913 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
1914 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
1915 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_6
.sin6_addr
, sizeof( addr_6
.sin6_addr
) );
1920 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_4
.sin_addr
);
1921 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
1922 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
1923 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_4
.sin_addr
, sizeof( addr_4
.sin_addr
) );
1926 (*hInfo
)->m_host
.h_addr_list
[1] = NULL
;
1927 (*hInfo
)->m_host
.h_addrtype
= family
;
1929 // Now get the aliases
1931 if ((tok
= strpbrk(tok
, " \t")) != NULL
)
1938 (*hInfo
)->m_host
.h_aliases
= (char**) malloc( sizeof(char**) * numAliases
);
1939 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
1940 (*hInfo
)->m_host
.h_aliases
[0] = NULL
;
1942 while ( tok
&& *tok
)
1944 // Skip over the whitespace, waiting for the start of the next alias name
1946 if (*tok
== ' ' || *tok
== '\t')
1952 // Check to make sure we don't exhaust the alias buffer
1954 if ( i
>= ( numAliases
- 1 ) )
1956 numAliases
= numAliases
* 2;
1957 (*hInfo
)->m_host
.h_aliases
= (char**) realloc( (*hInfo
)->m_host
.h_aliases
, numAliases
* sizeof( char** ) );
1958 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
1961 (*hInfo
)->m_host
.h_aliases
[i
] = (char*) malloc( strlen( tok
) + 1 );
1962 require_action( (*hInfo
)->m_host
.h_aliases
[i
], exit
, err
= kNoMemoryErr
);
1964 strcpy( (*hInfo
)->m_host
.h_aliases
[i
], tok
);
1966 if (( tok
= strpbrk( tok
, " \t")) != NULL
)
1971 (*hInfo
)->m_host
.h_aliases
[++i
] = NULL
;
1979 if ( err
&& ( *hInfo
) )
1981 HostsFileInfoFree( *hInfo
);