]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/mdnsNSP/mdnsNSP.c
mDNSResponder-107.1.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / mdnsNSP / mdnsNSP.c
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: mdnsNSP.c,v $
26 Revision 1.14 2005/03/29 20:35:28 shersche
27 <rdar://problem/4053899> Remove reverse lookup implementation due to NSP framework limitation
28
29 Revision 1.13 2005/03/29 19:42:47 shersche
30 Do label check before checking etc/hosts file
31
32 Revision 1.12 2005/03/21 00:42:45 shersche
33 <rdar://problem/4021486> Fix build warnings on Win32 platform
34
35 Revision 1.11 2005/03/16 03:04:51 shersche
36 <rdar://problem/4050633> Don't issue multicast query multilabel dot-local names
37
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
40
41 Revision 1.9 2005/02/01 01:45:55 shersche
42 Change mdnsNSP timeout to 2 seconds
43
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
46
47 Revision 1.7 2005/01/28 23:50:13 shersche
48 <rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
49 Bug #: 3942551
50
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
53 Bug #: 3789425
54
55 Revision 1.5 2004/07/13 21:24:28 rpantos
56 Fix for <rdar://problem/3701120>.
57
58 Revision 1.4 2004/07/09 18:03:33 shersche
59 removed extraneous DNSServiceQueryRecord call
60
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
63 Bug #: 3715582
64
65 Revision 1.2 2004/06/24 19:18:07 shersche
66 Rename to mdnsNSP
67 Submitted by: herscher
68
69 Revision 1.1 2004/06/18 04:13:44 rpantos
70 Move up one level.
71
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.
74
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.
78
79 */
80
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84
85 #include "CommonServices.h"
86 #include "DebugServices.h"
87
88 #include <guiddef.h>
89 #include <ws2spi.h>
90
91 #include "dns_sd.h"
92
93 #if 0
94 #pragma mark == Structures ==
95 #endif
96
97 //===========================================================================================================================
98 // Structures
99 //===========================================================================================================================
100
101 typedef struct Query * QueryRef;
102 typedef struct Query Query;
103 struct Query
104 {
105 QueryRef next;
106 int refCount;
107 DWORD querySetFlags;
108 WSAQUERYSETW * querySet;
109 size_t querySetSize;
110 HANDLE dataEvent;
111 HANDLE cancelEvent;
112 HANDLE waitHandles[ 2 ];
113 DWORD waitCount;
114 DNSServiceRef resolver;
115 char name[ kDNSServiceMaxDomainName ];
116 size_t nameSize;
117 uint32_t addr;
118 bool addrValid;
119 };
120
121 #define BUFFER_INITIAL_SIZE 4192
122 #define ALIASES_INITIAL_SIZE 5
123
124 typedef struct HostsFile
125 {
126 int m_bufferSize;
127 char * m_buffer;
128 FILE * m_fp;
129 } HostsFile;
130
131
132 typedef struct HostsFileInfo
133 {
134 struct hostent m_host;
135 struct HostsFileInfo * m_next;
136 } HostsFileInfo;
137
138
139 #if 0
140 #pragma mark == Prototypes ==
141 #endif
142
143 //===========================================================================================================================
144 // Prototypes
145 //===========================================================================================================================
146
147 // DLL Exports
148
149 BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
150 STDAPI DllRegisterServer( void );
151 STDAPI DllRegisterServer( void );
152
153
154 // NSP SPIs
155
156 int WSPAPI NSPCleanup( LPGUID inProviderID );
157
158 DEBUG_LOCAL int WSPAPI
159 NSPLookupServiceBegin(
160 LPGUID inProviderID,
161 LPWSAQUERYSETW inQuerySet,
162 LPWSASERVICECLASSINFOW inServiceClassInfo,
163 DWORD inFlags,
164 LPHANDLE outLookup );
165
166 DEBUG_LOCAL int WSPAPI
167 NSPLookupServiceNext(
168 HANDLE inLookup,
169 DWORD inFlags,
170 LPDWORD ioBufferLength,
171 LPWSAQUERYSETW outResults );
172
173 DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup );
174
175 DEBUG_LOCAL int WSPAPI
176 NSPSetService(
177 LPGUID inProviderID,
178 LPWSASERVICECLASSINFOW inServiceClassInfo,
179 LPWSAQUERYSETW inRegInfo,
180 WSAESETSERVICEOP inOperation,
181 DWORD inFlags );
182
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 );
186
187 // Private
188
189 #define NSPLock() EnterCriticalSection( &gLock );
190 #define NSPUnlock() LeaveCriticalSection( &gLock );
191
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 );
195
196 DEBUG_LOCAL void CALLBACK_COMPAT
197 QueryRecordCallback(
198 DNSServiceRef inRef,
199 DNSServiceFlags inFlags,
200 uint32_t inInterfaceIndex,
201 DNSServiceErrorType inErrorCode,
202 const char * inName,
203 uint16_t inRRType,
204 uint16_t inRRClass,
205 uint16_t inRDataSize,
206 const void * inRData,
207 uint32_t inTTL,
208 void * inContext );
209
210 DEBUG_LOCAL OSStatus
211 QueryCopyQuerySet(
212 QueryRef inRef,
213 const WSAQUERYSETW * inQuerySet,
214 DWORD inQuerySetFlags,
215 WSAQUERYSETW ** outQuerySet,
216 size_t * outSize );
217
218 DEBUG_LOCAL void
219 QueryCopyQuerySetTo(
220 QueryRef inRef,
221 const WSAQUERYSETW * inQuerySet,
222 DWORD inQuerySetFlags,
223 WSAQUERYSETW * outQuerySet );
224
225 DEBUG_LOCAL size_t QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags );
226
227 #if( DEBUG )
228 void DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet );
229
230 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
231 #else
232 #define dlog_query_set( LEVEL, SET )
233 #endif
234
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] );
243
244 #ifdef ENABLE_REVERSE_LOOKUP
245 DEBUG_LOCAL OSStatus IsReverseLookup( LPCWSTR name, size_t size );
246 #endif
247
248
249 #if 0
250 #pragma mark == Globals ==
251 #endif
252
253 //===========================================================================================================================
254 // Globals
255 //===========================================================================================================================
256
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;
267
268 #if 0
269 #pragma mark -
270 #endif
271
272 //===========================================================================================================================
273 // DllMain
274 //===========================================================================================================================
275
276 BOOL APIENTRY DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
277 {
278 DEBUG_USE_ONLY( inInstance );
279 DEBUG_UNUSED( inReserved );
280
281 switch( inReason )
282 {
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__ );
290 break;
291
292 case DLL_PROCESS_DETACH:
293 HostsFileInfoFree( gHostsFileInfo );
294 gHostsFileInfo = NULL;
295 dlog( kDebugLevelVerbose, "%s: process detach\n", __ROUTINE__ );
296 break;
297
298 case DLL_THREAD_ATTACH:
299 dlog( kDebugLevelVerbose, "%s: thread attach\n", __ROUTINE__ );
300 break;
301
302 case DLL_THREAD_DETACH:
303 dlog( kDebugLevelVerbose, "%s: thread detach\n", __ROUTINE__ );
304 break;
305
306 default:
307 dlog( kDebugLevelNotice, "%s: unknown reason code (%d)\n", __ROUTINE__, inReason );
308 break;
309 }
310 return( TRUE );
311 }
312
313
314 //===========================================================================================================================
315 // DllRegisterServer
316 //===========================================================================================================================
317
318 STDAPI DllRegisterServer( void )
319 {
320 WSADATA wsd;
321 WCHAR path[ MAX_PATH ];
322 HRESULT err;
323
324 dlog( kDebugLevelTrace, "DllRegisterServer\n" );
325
326 err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
327 err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
328 require_noerr( err, exit );
329
330 // Unregister before registering to workaround an installer
331 // problem during upgrade installs.
332
333 WSCUnInstallNameSpace( &gNSPGUID );
334
335 err = GetModuleFileNameW( gInstance, path, sizeof( path ) );
336 err = translate_errno( err != 0, errno_compat(), kUnknownErr );
337 require_noerr( err, exit );
338
339 err = WSCInstallNameSpace( gNSPName, path, NS_DNS, 1, &gNSPGUID );
340 err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
341 require_noerr( err, exit );
342
343 exit:
344
345 WSACleanup();
346 return( err );
347 }
348
349 //===========================================================================================================================
350 // DllUnregisterServer
351 //===========================================================================================================================
352
353 STDAPI DllUnregisterServer( void )
354 {
355 WSADATA wsd;
356 HRESULT err;
357
358 dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
359
360 err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
361 err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
362 require_noerr( err, exit );
363
364 err = WSCUnInstallNameSpace( &gNSPGUID );
365 err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
366 require_noerr( err, exit );
367
368 exit:
369
370 WSACleanup();
371 return err;
372 }
373
374
375 //===========================================================================================================================
376 // NSPStartup
377 //
378 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
379 //===========================================================================================================================
380
381 int WSPAPI NSPStartup( LPGUID inProviderID, LPNSP_ROUTINE outRoutines )
382 {
383 OSStatus err;
384
385 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
386 dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
387
388 // Only initialize if this is the first time NSPStartup is called.
389
390 if( InterlockedIncrement( &gRefCount ) != 1 )
391 {
392 err = NO_ERROR;
393 goto exit;
394 }
395
396 // Initialize our internal state.
397
398 InitializeCriticalSection( &gLock );
399 gLockInitialized = true;
400
401 // Set the size to exclude NSPIoctl because we don't implement it.
402
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;
414
415 err = NO_ERROR;
416
417 exit:
418 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
419 if( err != NO_ERROR )
420 {
421 NSPCleanup( inProviderID );
422 SetLastError( (DWORD) err );
423 return( SOCKET_ERROR );
424 }
425 return( NO_ERROR );
426 }
427
428 //===========================================================================================================================
429 // NSPCleanup
430 //
431 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
432 //===========================================================================================================================
433
434 int WSPAPI NSPCleanup( LPGUID inProviderID )
435 {
436 DEBUG_USE_ONLY( inProviderID );
437
438 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
439 dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
440
441 // Only initialize if this is the first time NSPStartup is called.
442
443 if( InterlockedDecrement( &gRefCount ) != 0 )
444 {
445 goto exit;
446 }
447
448 // Stop any outstanding queries.
449
450 if( gLockInitialized )
451 {
452 NSPLock();
453 }
454 while( gQueryList )
455 {
456 check_string( gQueryList->refCount == 1, "NSPCleanup with outstanding queries!" );
457 QueryRelease( gQueryList );
458 }
459 if( gLockInitialized )
460 {
461 NSPUnlock();
462 }
463
464 // Shut down DNS-SD and release our resources.
465
466 if( gDNSSDInitialized )
467 {
468 gDNSSDInitialized = false;
469 }
470 if( gLockInitialized )
471 {
472 gLockInitialized = false;
473 DeleteCriticalSection( &gLock );
474 }
475
476 exit:
477 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
478 return( NO_ERROR );
479 }
480
481 //===========================================================================================================================
482 // NSPLookupServiceBegin
483 //
484 // This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
485 // that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
486 // opposed to specifying the query parameters each time.
487 //===========================================================================================================================
488
489 DEBUG_LOCAL int WSPAPI
490 NSPLookupServiceBegin(
491 LPGUID inProviderID,
492 LPWSAQUERYSETW inQuerySet,
493 LPWSASERVICECLASSINFOW inServiceClassInfo,
494 DWORD inFlags,
495 LPHANDLE outLookup )
496 {
497 OSStatus err;
498 QueryRef obj;
499 LPCWSTR name;
500 size_t size;
501 LPCWSTR p;
502 DWORD type;
503 DWORD n;
504 DWORD i;
505 INT family;
506 INT protocol;
507
508 DEBUG_UNUSED( inProviderID );
509 DEBUG_UNUSED( inServiceClassInfo );
510
511 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
512
513 obj = NULL;
514 require_action( inQuerySet, exit, err = WSAEINVAL );
515 name = inQuerySet->lpszServiceInstanceName;
516 require_action_quiet( name, exit, err = WSAEINVAL );
517 require_action( outLookup, exit, err = WSAEINVAL );
518
519 dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__, inFlags, name );
520 dlog_query_set( kDebugLevelVerbose, inQuerySet );
521
522 // Check if we can handle this type of request and if we support any of the protocols being requested.
523 // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
524
525 require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
526
527 type = inQuerySet->dwNameSpace;
528 require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
529
530 n = inQuerySet->dwNumberOfProtocols;
531 if( n > 0 )
532 {
533 require_action( inQuerySet->lpafpProtocols, exit, err = WSAEINVAL );
534 for( i = 0; i < n; ++i )
535 {
536 family = inQuerySet->lpafpProtocols[ i ].iAddressFamily;
537 protocol = inQuerySet->lpafpProtocols[ i ].iProtocol;
538 if( ( family == AF_INET ) && ( ( protocol == IPPROTO_UDP ) || ( protocol == IPPROTO_TCP ) ) )
539 {
540 break;
541 }
542 }
543 require_action_quiet( i < n, exit, err = WSASERVICE_NOT_FOUND );
544 }
545
546 // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
547 // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
548 // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
549 // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
550 // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
551
552 for( p = name; *p; ++p ) {} // Find end of string
553 size = (size_t)( p - name );
554 require_action_quiet( size > sizeof_string( ".local" ), exit, err = WSASERVICE_NOT_FOUND );
555
556 p = name + ( size - 1 );
557 p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
558 if ( ( ( p[ 0 ] != '.' ) ||
559 ( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) ) ||
560 ( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) ) ||
561 ( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) ) ||
562 ( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) ) ||
563 ( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
564 {
565 #ifdef ENABLE_REVERSE_LOOKUP
566
567 err = IsReverseLookup( name, size );
568
569 #else
570
571 err = WSASERVICE_NOT_FOUND;
572
573 #endif
574
575 require_noerr( err, exit );
576 }
577 else
578 {
579 const char * replyDomain;
580 char translated[ kDNSServiceMaxDomainName ];
581 int n;
582 int labels = 0;
583 const char * label[128];
584 char text[64];
585
586 n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL );
587 require_action( n > 0, exit, err = WSASERVICE_NOT_FOUND );
588
589 // <rdar://problem/4050633>
590
591 // Don't resolve multi-label name
592
593 replyDomain = translated;
594
595 while ( *replyDomain )
596 {
597 label[labels++] = replyDomain;
598 replyDomain = GetNextLabel(replyDomain, text);
599 }
600
601 require_action( labels == 2, exit, err = WSASERVICE_NOT_FOUND );
602
603 // <rdar://problem/3936771>
604 //
605 // Check to see if the name of this host is in the hosts table. If so,
606 // don't try and resolve it
607
608 require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
609 }
610
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.
612
613 NSPLock();
614 if( !gDNSSDInitialized )
615 {
616 gDNSSDInitialized = true;
617 }
618
619 err = QueryCreate( inQuerySet, inFlags, &obj );
620 NSPUnlock();
621 require_noerr( err, exit );
622
623 *outLookup = (HANDLE) obj;
624
625 exit:
626 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
627 if( err != NO_ERROR )
628 {
629 SetLastError( (DWORD) err );
630 return( SOCKET_ERROR );
631 }
632 return( NO_ERROR );
633 }
634
635 //===========================================================================================================================
636 // NSPLookupServiceNext
637 //
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 //===========================================================================================================================
642
643 DEBUG_LOCAL int WSPAPI
644 NSPLookupServiceNext(
645 HANDLE inLookup,
646 DWORD inFlags,
647 LPDWORD ioSize,
648 LPWSAQUERYSETW outResults )
649 {
650 OSStatus err;
651 QueryRef obj;
652 DWORD waitResult;
653 size_t size;
654
655 DEBUG_USE_ONLY( inFlags );
656
657 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
658
659 obj = NULL;
660 NSPLock();
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 );
666
667 dlog( kDebugLevelTrace, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__, inLookup, inFlags, *ioSize );
668
669 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
670
671 NSPUnlock();
672 waitResult = WaitForMultipleObjects( obj->waitCount, obj->waitHandles, FALSE, 2 * 1000 );
673 NSPLock();
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 );
679
680 // Copy the externalized query results to the callers buffer (if it fits).
681
682 size = QueryCopyQuerySetSize( obj, obj->querySet, obj->querySetFlags );
683 require_action( size <= (size_t) *ioSize, exit, err = WSAEFAULT );
684
685 QueryCopyQuerySetTo( obj, obj->querySet, obj->querySetFlags, outResults );
686 outResults->dwOutputFlags = RESULT_IS_ADDED;
687 obj->addrValid = false;
688
689 exit:
690 if( obj )
691 {
692 QueryRelease( obj );
693 }
694 NSPUnlock();
695 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
696 if( err != NO_ERROR )
697 {
698 SetLastError( (DWORD) err );
699 return( SOCKET_ERROR );
700 }
701 return( NO_ERROR );
702 }
703
704 //===========================================================================================================================
705 // NSPLookupServiceEnd
706 //
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 //===========================================================================================================================
711
712 DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup )
713 {
714 OSStatus err;
715
716 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
717
718 dlog( kDebugLevelTrace, "%s (lookup=%#p)\n", __ROUTINE__, inLookup );
719
720 NSPLock();
721 err = QueryRelease( (QueryRef) inLookup );
722 NSPUnlock();
723 require_noerr( err, exit );
724
725 exit:
726 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
727 if( err != NO_ERROR )
728 {
729 SetLastError( (DWORD) err );
730 return( SOCKET_ERROR );
731 }
732 return( NO_ERROR );
733 }
734
735 //===========================================================================================================================
736 // NSPSetService
737 //
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 //===========================================================================================================================
743
744 DEBUG_LOCAL int WSPAPI
745 NSPSetService(
746 LPGUID inProviderID,
747 LPWSASERVICECLASSINFOW inServiceClassInfo,
748 LPWSAQUERYSETW inRegInfo,
749 WSAESETSERVICEOP inOperation,
750 DWORD inFlags )
751 {
752 DEBUG_UNUSED( inProviderID );
753 DEBUG_UNUSED( inServiceClassInfo );
754 DEBUG_UNUSED( inRegInfo );
755 DEBUG_UNUSED( inOperation );
756 DEBUG_UNUSED( inFlags );
757
758 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
759 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
760
761 // We don't allow services to be registered so always return an error.
762
763 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
764 return( WSAEINVAL );
765 }
766
767 //===========================================================================================================================
768 // NSPInstallServiceClass
769 //
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 //===========================================================================================================================
774
775 DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo )
776 {
777 DEBUG_UNUSED( inProviderID );
778 DEBUG_UNUSED( inServiceClassInfo );
779
780 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
781 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
782
783 // We don't allow service classes to be installed so always return an error.
784
785 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
786 return( WSA_INVALID_PARAMETER );
787 }
788
789 //===========================================================================================================================
790 // NSPRemoveServiceClass
791 //
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
794 // service class.
795 //===========================================================================================================================
796
797 DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID )
798 {
799 DEBUG_UNUSED( inProviderID );
800 DEBUG_UNUSED( inServiceClassID );
801
802 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
803 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
804
805 // We don't allow service classes to be installed so always return an error.
806
807 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
808 return( WSATYPE_NOT_FOUND );
809 }
810
811 //===========================================================================================================================
812 // NSPGetServiceClassInfo
813 //
814 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
815 // a given service class.
816 //===========================================================================================================================
817
818 DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioSize, LPWSASERVICECLASSINFOW ioServiceClassInfo )
819 {
820 DEBUG_UNUSED( inProviderID );
821 DEBUG_UNUSED( ioSize );
822 DEBUG_UNUSED( ioServiceClassInfo );
823
824 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
825 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
826
827 // We don't allow service classes to be installed so always return an error.
828
829 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
830 return( WSATYPE_NOT_FOUND );
831 }
832
833 #if 0
834 #pragma mark -
835 #endif
836
837 //===========================================================================================================================
838 // QueryCreate
839 //
840 // Warning: Assumes the NSP lock is held.
841 //===========================================================================================================================
842
843 DEBUG_LOCAL OSStatus QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef )
844 {
845 OSStatus err;
846 QueryRef obj;
847 char name[ kDNSServiceMaxDomainName ];
848 int n;
849 QueryRef * p;
850
851 obj = NULL;
852 check( inQuerySet );
853 check( inQuerySet->lpszServiceInstanceName );
854 check( outRef );
855
856 // Convert the wchar_t name to UTF-8.
857
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 );
861
862 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
863
864 obj = (QueryRef) calloc( 1, sizeof( *obj ) );
865 require_action( obj, exit, err = WSA_NOT_ENOUGH_MEMORY );
866
867 obj->refCount = 1;
868
869 for( p = &gQueryList; *p; p = &( *p )->next ) {} // Find the end of the list.
870 *p = obj;
871
872 // Set up events to signal when data is ready and when cancelling.
873
874 obj->dataEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
875 require_action( obj->dataEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
876
877 obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
878 require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
879
880 // Start the query.
881
882 err = DNSServiceQueryRecord( &obj->resolver, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN,
883 QueryRecordCallback, obj );
884 require_noerr( err, exit );
885
886 // Attach the socket to the event
887
888 WSAEventSelect(DNSServiceRefSockFD(obj->resolver), obj->dataEvent, FD_READ|FD_CLOSE);
889
890 obj->waitCount = 0;
891 obj->waitHandles[ obj->waitCount++ ] = obj->dataEvent;
892 obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
893 check( obj->waitCount == sizeof_array( obj->waitHandles ) );
894
895 // Copy the QuerySet so it can be returned later.
896
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 );
901
902 // Success!
903
904 *outRef = obj;
905 obj = NULL;
906 err = NO_ERROR;
907
908 exit:
909 if( obj )
910 {
911 QueryRelease( obj );
912 }
913 return( err );
914 }
915
916 //===========================================================================================================================
917 // QueryRetain
918 //
919 // Warning: Assumes the NSP lock is held.
920 //===========================================================================================================================
921
922 DEBUG_LOCAL OSStatus QueryRetain( QueryRef inRef )
923 {
924 OSStatus err;
925 QueryRef obj;
926
927 for( obj = gQueryList; obj; obj = obj->next )
928 {
929 if( obj == inRef )
930 {
931 break;
932 }
933 }
934 require_action( obj, exit, err = WSA_INVALID_HANDLE );
935
936 ++inRef->refCount;
937 err = NO_ERROR;
938
939 exit:
940 return( err );
941 }
942
943 //===========================================================================================================================
944 // QueryRelease
945 //
946 // Warning: Assumes the NSP lock is held.
947 //===========================================================================================================================
948
949 DEBUG_LOCAL OSStatus QueryRelease( QueryRef inRef )
950 {
951 OSStatus err;
952 QueryRef * p;
953 BOOL ok;
954
955 // Find the item in the list.
956
957 for( p = &gQueryList; *p; p = &( *p )->next )
958 {
959 if( *p == inRef )
960 {
961 break;
962 }
963 }
964 require_action( *p, exit, err = WSA_INVALID_HANDLE );
965
966 // Signal a cancel to unblock any threads waiting for results.
967
968 if( inRef->cancelEvent )
969 {
970 ok = SetEvent( inRef->cancelEvent );
971 check_translated_errno( ok, GetLastError(), WSAEINVAL );
972 }
973
974 // Stop the query.
975
976 if( inRef->resolver )
977 {
978 DNSServiceRefDeallocate( inRef->resolver );
979 inRef->resolver = NULL;
980 }
981
982 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
983
984 if( --inRef->refCount != 0 )
985 {
986 err = NO_ERROR;
987 goto exit;
988 }
989 *p = inRef->next;
990
991 // Release resources.
992
993 if( inRef->cancelEvent )
994 {
995 ok = CloseHandle( inRef->cancelEvent );
996 check_translated_errno( ok, GetLastError(), WSAEINVAL );
997 }
998 if( inRef->dataEvent )
999 {
1000 ok = CloseHandle( inRef->dataEvent );
1001 check_translated_errno( ok, GetLastError(), WSAEINVAL );
1002 }
1003 if( inRef->querySet )
1004 {
1005 free( inRef->querySet );
1006 }
1007 free( inRef );
1008 err = NO_ERROR;
1009
1010 exit:
1011 return( err );
1012 }
1013
1014 //===========================================================================================================================
1015 // QueryRecordCallback
1016 //===========================================================================================================================
1017
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,
1025 uint16_t inRRType,
1026 uint16_t inRRClass,
1027 uint16_t inRDataSize,
1028 const void * inRData,
1029 uint32_t inTTL,
1030 void * inContext )
1031 {
1032 QueryRef obj;
1033 const char * src;
1034 char * dst;
1035 BOOL ok;
1036
1037 DEBUG_UNUSED( inFlags );
1038 DEBUG_UNUSED( inInterfaceIndex );
1039 DEBUG_UNUSED( inTTL );
1040
1041 NSPLock();
1042 obj = (QueryRef) inContext;
1043 check( obj );
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 );
1049
1050 dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1051 __ROUTINE__, inFlags, inName, inRRType, inRDataSize );
1052
1053 // Copy the name if needed.
1054
1055 if( obj->name[ 0 ] == '\0' )
1056 {
1057 src = inName;
1058 dst = obj->name;
1059 while( *src != '\0' )
1060 {
1061 *dst++ = *src++;
1062 }
1063 *dst = '\0';
1064 obj->nameSize = (size_t)( dst - obj->name );
1065 check( obj->nameSize < sizeof( obj->name ) );
1066 }
1067
1068 // Copy the data.
1069
1070 memcpy( &obj->addr, inRData, inRDataSize );
1071 obj->addrValid = true;
1072
1073 // Signal that a result is ready.
1074
1075 check( obj->dataEvent );
1076 ok = SetEvent( obj->dataEvent );
1077 check_translated_errno( ok, GetLastError(), WSAEINVAL );
1078
1079 // Stop the resolver after the first response.
1080
1081 DNSServiceRefDeallocate( inRef );
1082 obj->resolver = NULL;
1083
1084 exit:
1085 NSPUnlock();
1086 }
1087
1088 #if 0
1089 #pragma mark -
1090 #endif
1091
1092 //===========================================================================================================================
1093 // QueryCopyQuerySet
1094 //
1095 // Warning: Assumes the NSP lock is held.
1096 //===========================================================================================================================
1097
1098 DEBUG_LOCAL OSStatus
1099 QueryCopyQuerySet(
1100 QueryRef inRef,
1101 const WSAQUERYSETW * inQuerySet,
1102 DWORD inQuerySetFlags,
1103 WSAQUERYSETW ** outQuerySet,
1104 size_t * outSize )
1105 {
1106 OSStatus err;
1107 size_t size;
1108 WSAQUERYSETW * qs;
1109
1110 check( inQuerySet );
1111 check( outQuerySet );
1112
1113 size = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
1114 qs = (WSAQUERYSETW *) calloc( 1, size );
1115 require_action( qs, exit, err = WSA_NOT_ENOUGH_MEMORY );
1116
1117 QueryCopyQuerySetTo( inRef, inQuerySet, inQuerySetFlags, qs );
1118
1119 *outQuerySet = qs;
1120 if( outSize )
1121 {
1122 *outSize = size;
1123 }
1124 qs = NULL;
1125 err = NO_ERROR;
1126
1127 exit:
1128 if( qs )
1129 {
1130 free( qs );
1131 }
1132 return( err );
1133 }
1134
1135 //===========================================================================================================================
1136 // QueryCopyQuerySetTo
1137 //
1138 // Warning: Assumes the NSP lock is held.
1139 //===========================================================================================================================
1140
1141 DEBUG_LOCAL void
1142 QueryCopyQuerySetTo(
1143 QueryRef inRef,
1144 const WSAQUERYSETW * inQuerySet,
1145 DWORD inQuerySetFlags,
1146 WSAQUERYSETW * outQuerySet )
1147 {
1148 uint8_t * dst;
1149 LPCWSTR s;
1150 LPWSTR q;
1151 DWORD n;
1152 DWORD i;
1153
1154 #if( DEBUG )
1155 size_t debugSize;
1156
1157 debugSize = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
1158 #endif
1159
1160 check( inQuerySet );
1161 check( outQuerySet );
1162
1163 dst = (uint8_t *) outQuerySet;
1164
1165 // Copy the static portion of the results.
1166
1167 *outQuerySet = *inQuerySet;
1168 dst += sizeof( *inQuerySet );
1169
1170 if( inQuerySetFlags & LUP_RETURN_NAME )
1171 {
1172 s = inQuerySet->lpszServiceInstanceName;
1173 if( s )
1174 {
1175 outQuerySet->lpszServiceInstanceName = (LPWSTR) dst;
1176 q = (LPWSTR) dst;
1177 while( ( *q++ = *s++ ) != 0 ) {}
1178 dst = (uint8_t *) q;
1179 }
1180 }
1181 else
1182 {
1183 outQuerySet->lpszServiceInstanceName = NULL;
1184 }
1185
1186 if( inQuerySet->lpServiceClassId )
1187 {
1188 outQuerySet->lpServiceClassId = (LPGUID) dst;
1189 *outQuerySet->lpServiceClassId = *inQuerySet->lpServiceClassId;
1190 dst += sizeof( *inQuerySet->lpServiceClassId );
1191 }
1192
1193 if( inQuerySet->lpVersion )
1194 {
1195 outQuerySet->lpVersion = (LPWSAVERSION) dst;
1196 *outQuerySet->lpVersion = *inQuerySet->lpVersion;
1197 dst += sizeof( *inQuerySet->lpVersion );
1198 }
1199
1200 s = inQuerySet->lpszComment;
1201 if( s )
1202 {
1203 outQuerySet->lpszComment = (LPWSTR) dst;
1204 q = (LPWSTR) dst;
1205 while( ( *q++ = *s++ ) != 0 ) {}
1206 dst = (uint8_t *) q;
1207 }
1208
1209 if( inQuerySet->lpNSProviderId )
1210 {
1211 outQuerySet->lpNSProviderId = (LPGUID) dst;
1212 *outQuerySet->lpNSProviderId = *inQuerySet->lpNSProviderId;
1213 dst += sizeof( *inQuerySet->lpNSProviderId );
1214 }
1215
1216 s = inQuerySet->lpszContext;
1217 if( s )
1218 {
1219 outQuerySet->lpszContext = (LPWSTR) dst;
1220 q = (LPWSTR) dst;
1221 while( ( *q++ = *s++ ) != 0 ) {}
1222 dst = (uint8_t *) q;
1223 }
1224
1225 n = inQuerySet->dwNumberOfProtocols;
1226 if( n > 0 )
1227 {
1228 check( inQuerySet->lpafpProtocols );
1229
1230 outQuerySet->lpafpProtocols = (LPAFPROTOCOLS) dst;
1231 for( i = 0; i < n; ++i )
1232 {
1233 outQuerySet->lpafpProtocols[ i ] = inQuerySet->lpafpProtocols[ i ];
1234 dst += sizeof( *inQuerySet->lpafpProtocols );
1235 }
1236 }
1237
1238 s = inQuerySet->lpszQueryString;
1239 if( s )
1240 {
1241 outQuerySet->lpszQueryString = (LPWSTR) dst;
1242 q = (LPWSTR) dst;
1243 while( ( *q++ = *s++ ) != 0 ) {}
1244 dst = (uint8_t *) q;
1245 }
1246
1247 // Copy the address(es).
1248
1249 if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addrValid )
1250 {
1251 struct sockaddr_in * addr;
1252
1253 outQuerySet->dwNumberOfCsAddrs = 1;
1254 outQuerySet->lpcsaBuffer = (LPCSADDR_INFO) dst;
1255 dst += sizeof( *outQuerySet->lpcsaBuffer );
1256
1257 outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.lpSockaddr = NULL;
1258 outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.iSockaddrLength = 0;
1259
1260 outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.lpSockaddr = (LPSOCKADDR) dst;
1261 outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.iSockaddrLength = sizeof( struct sockaddr_in );
1262
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 );
1268
1269 outQuerySet->lpcsaBuffer[ 0 ].iSocketType = AF_INET; // Emulate Tcpip NSP
1270 outQuerySet->lpcsaBuffer[ 0 ].iProtocol = IPPROTO_UDP; // Emulate Tcpip NSP
1271 }
1272 else
1273 {
1274 outQuerySet->dwNumberOfCsAddrs = 0;
1275 outQuerySet->lpcsaBuffer = NULL;
1276 }
1277
1278 // Copy the hostent blob.
1279
1280 if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
1281 {
1282 uint8_t * base;
1283 struct hostent * he;
1284 uintptr_t * p;
1285
1286 outQuerySet->lpBlob = (LPBLOB) dst;
1287 dst += sizeof( *outQuerySet->lpBlob );
1288
1289 base = dst;
1290 he = (struct hostent *) dst;
1291 dst += sizeof( *he );
1292
1293 he->h_name = (char *)( dst - base );
1294 memcpy( dst, inRef->name, inRef->nameSize + 1 );
1295 dst += ( inRef->nameSize + 1 );
1296
1297 he->h_aliases = (char **)( dst - base );
1298 p = (uintptr_t *) dst;
1299 *p++ = 0;
1300 dst = (uint8_t *) p;
1301
1302 he->h_addrtype = AF_INET;
1303 he->h_length = 4;
1304
1305 he->h_addr_list = (char **)( dst - base );
1306 p = (uintptr_t *) dst;
1307 dst += ( 2 * sizeof( *p ) );
1308 *p++ = (uintptr_t)( dst - base );
1309 *p++ = 0;
1310 p = (uintptr_t *) dst;
1311 *p++ = (uintptr_t) inRef->addr;
1312 dst = (uint8_t *) p;
1313
1314 outQuerySet->lpBlob->cbSize = (ULONG)( dst - base );
1315 outQuerySet->lpBlob->pBlobData = (BYTE *) base;
1316 }
1317 dlog_query_set( kDebugLevelVerbose, outQuerySet );
1318
1319 check( (size_t)( dst - ( (uint8_t *) outQuerySet ) ) == debugSize );
1320 }
1321
1322 //===========================================================================================================================
1323 // QueryCopyQuerySetSize
1324 //
1325 // Warning: Assumes the NSP lock is held.
1326 //===========================================================================================================================
1327
1328 DEBUG_LOCAL size_t QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags )
1329 {
1330 size_t size;
1331 LPCWSTR s;
1332 LPCWSTR p;
1333
1334 check( inRef );
1335 check( inQuerySet );
1336
1337 // Calculate the size of the static portion of the results.
1338
1339 size = sizeof( *inQuerySet );
1340
1341 if( inQuerySetFlags & LUP_RETURN_NAME )
1342 {
1343 s = inQuerySet->lpszServiceInstanceName;
1344 if( s )
1345 {
1346 for( p = s; *p; ++p ) {}
1347 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1348 }
1349 }
1350
1351 if( inQuerySet->lpServiceClassId )
1352 {
1353 size += sizeof( *inQuerySet->lpServiceClassId );
1354 }
1355
1356 if( inQuerySet->lpVersion )
1357 {
1358 size += sizeof( *inQuerySet->lpVersion );
1359 }
1360
1361 s = inQuerySet->lpszComment;
1362 if( s )
1363 {
1364 for( p = s; *p; ++p ) {}
1365 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1366 }
1367
1368 if( inQuerySet->lpNSProviderId )
1369 {
1370 size += sizeof( *inQuerySet->lpNSProviderId );
1371 }
1372
1373 s = inQuerySet->lpszContext;
1374 if( s )
1375 {
1376 for( p = s; *p; ++p ) {}
1377 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1378 }
1379
1380 size += ( inQuerySet->dwNumberOfProtocols * sizeof( *inQuerySet->lpafpProtocols ) );
1381
1382 s = inQuerySet->lpszQueryString;
1383 if( s )
1384 {
1385 for( p = s; *p; ++p ) {}
1386 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1387 }
1388
1389 // Calculate the size of the address(es).
1390
1391 if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addrValid )
1392 {
1393 size += sizeof( *inQuerySet->lpcsaBuffer );
1394 size += sizeof( struct sockaddr_in );
1395 }
1396
1397 // Calculate the size of the hostent blob.
1398
1399 if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
1400 {
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
1408 }
1409 return( size );
1410 }
1411
1412 #if 0
1413 #pragma mark -
1414 #endif
1415
1416 #if( DEBUG )
1417 //===========================================================================================================================
1418 // DebugDumpQuerySet
1419 //===========================================================================================================================
1420
1421 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1422 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1423
1424 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1425 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1426
1427 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1428
1429 void DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet )
1430 {
1431 DWORD i;
1432
1433 check( inQuerySet );
1434
1435 // Fixed portion of the QuerySet.
1436
1437 dlog( inLevel, "QuerySet:\n" );
1438 dlog( inLevel, " dwSize: %d (expected %d)\n", inQuerySet->dwSize, sizeof( *inQuerySet ) );
1439 if( inQuerySet->lpszServiceInstanceName )
1440 {
1441 dlog( inLevel, " lpszServiceInstanceName: %S\n", inQuerySet->lpszServiceInstanceName );
1442 }
1443 else
1444 {
1445 dlog( inLevel, " lpszServiceInstanceName: <null>\n" );
1446 }
1447 if( inQuerySet->lpServiceClassId )
1448 {
1449 dlog( inLevel, " lpServiceClassId: %U\n", inQuerySet->lpServiceClassId );
1450 }
1451 else
1452 {
1453 dlog( inLevel, " lpServiceClassId: <null>\n" );
1454 }
1455 if( inQuerySet->lpVersion )
1456 {
1457 dlog( inLevel, " lpVersion:\n" );
1458 dlog( inLevel, " dwVersion: %d\n", inQuerySet->lpVersion->dwVersion );
1459 dlog( inLevel, " dwVersion: %d\n", inQuerySet->lpVersion->ecHow );
1460 }
1461 else
1462 {
1463 dlog( inLevel, " lpVersion: <null>\n" );
1464 }
1465 if( inQuerySet->lpszComment )
1466 {
1467 dlog( inLevel, " lpszComment: %S\n", inQuerySet->lpszComment );
1468 }
1469 else
1470 {
1471 dlog( inLevel, " lpszComment: <null>\n" );
1472 }
1473 dlog( inLevel, " dwNameSpace: %d %s\n", inQuerySet->dwNameSpace,
1474 DebugNameSpaceToString( inQuerySet->dwNameSpace ) );
1475 if( inQuerySet->lpNSProviderId )
1476 {
1477 dlog( inLevel, " lpNSProviderId: %U\n", inQuerySet->lpNSProviderId );
1478 }
1479 else
1480 {
1481 dlog( inLevel, " lpNSProviderId: <null>\n" );
1482 }
1483 if( inQuerySet->lpszContext )
1484 {
1485 dlog( inLevel, " lpszContext: %S\n", inQuerySet->lpszContext );
1486 }
1487 else
1488 {
1489 dlog( inLevel, " lpszContext: <null>\n" );
1490 }
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 )
1494 {
1495 if( i != 0 )
1496 {
1497 dlog( inLevel, "\n" );
1498 }
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 ) );
1503 }
1504 if( inQuerySet->lpszQueryString )
1505 {
1506 dlog( inLevel, " lpszQueryString: %S\n", inQuerySet->lpszQueryString );
1507 }
1508 else
1509 {
1510 dlog( inLevel, " lpszQueryString: <null>\n" );
1511 }
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 )
1515 {
1516 if( i != 0 )
1517 {
1518 dlog( inLevel, "\n" );
1519 }
1520 if( inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr &&
1521 ( inQuerySet->lpcsaBuffer[ i ].LocalAddr.iSockaddrLength > 0 ) )
1522 {
1523 dlog( inLevel, " LocalAddr: %##a\n",
1524 inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr );
1525 }
1526 else
1527 {
1528 dlog( inLevel, " LocalAddr: <null/empty>\n" );
1529 }
1530 if( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr &&
1531 ( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.iSockaddrLength > 0 ) )
1532 {
1533 dlog( inLevel, " RemoteAddr: %##a\n",
1534 inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr );
1535 }
1536 else
1537 {
1538 dlog( inLevel, " RemoteAddr: <null/empty>\n" );
1539 }
1540 dlog( inLevel, " iSocketType: %d\n", inQuerySet->lpcsaBuffer[ i ].iSocketType );
1541 dlog( inLevel, " iProtocol: %d\n", inQuerySet->lpcsaBuffer[ i ].iProtocol );
1542 }
1543 dlog( inLevel, " dwOutputFlags: %d\n", inQuerySet->dwOutputFlags );
1544
1545 // Blob portion of the QuerySet.
1546
1547 if( inQuerySet->lpBlob )
1548 {
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 );
1555 }
1556 else
1557 {
1558 dlog( inLevel, " lpBlob: <null>\n" );
1559 }
1560 }
1561 #endif
1562
1563
1564 //===========================================================================================================================
1565 // InHostsTable
1566 //===========================================================================================================================
1567
1568 DEBUG_LOCAL BOOL
1569 InHostsTable( const char * name )
1570 {
1571 HostsFileInfo * node;
1572 BOOL ret = FALSE;
1573 OSStatus err;
1574
1575 check( name );
1576
1577 if ( gHostsFileInfo == NULL )
1578 {
1579 TCHAR systemDirectory[MAX_PATH];
1580 TCHAR hFileName[MAX_PATH];
1581 HostsFile * hFile;
1582
1583 GetSystemDirectory( systemDirectory, sizeof( systemDirectory ) );
1584 sprintf( hFileName, "%s\\drivers\\etc\\hosts", systemDirectory );
1585 err = HostsFileOpen( &hFile, hFileName );
1586 require_noerr( err, exit );
1587
1588 while ( HostsFileNext( hFile, &node ) == 0 )
1589 {
1590 if ( IsLocalName( node ) )
1591 {
1592 node->m_next = gHostsFileInfo;
1593 gHostsFileInfo = node;
1594 }
1595 else
1596 {
1597 HostsFileInfoFree( node );
1598 }
1599 }
1600
1601 HostsFileClose( hFile );
1602 }
1603
1604 for ( node = gHostsFileInfo; node; node = node->m_next )
1605 {
1606 if ( IsSameName( node, name ) )
1607 {
1608 ret = TRUE;
1609 break;
1610 }
1611 }
1612
1613 exit:
1614
1615 return ret;
1616 }
1617
1618
1619 //===========================================================================================================================
1620 // IsLocalName
1621 //===========================================================================================================================
1622
1623 DEBUG_LOCAL BOOL
1624 IsLocalName( HostsFileInfo * node )
1625 {
1626 BOOL ret = TRUE;
1627
1628 check( node );
1629
1630 if ( strstr( node->m_host.h_name, ".local" ) == NULL )
1631 {
1632 int i;
1633
1634 for ( i = 0; node->m_host.h_aliases[i]; i++ )
1635 {
1636 if ( strstr( node->m_host.h_aliases[i], ".local" ) )
1637 {
1638 goto exit;
1639 }
1640 }
1641
1642 ret = FALSE;
1643 }
1644
1645 exit:
1646
1647 return ret;
1648 }
1649
1650
1651 //===========================================================================================================================
1652 // IsSameName
1653 //===========================================================================================================================
1654
1655 DEBUG_LOCAL BOOL
1656 IsSameName( HostsFileInfo * node, const char * name )
1657 {
1658 BOOL ret = TRUE;
1659
1660 check( node );
1661 check( name );
1662
1663 if ( strcmp( node->m_host.h_name, name ) != 0 )
1664 {
1665 int i;
1666
1667 for ( i = 0; node->m_host.h_aliases[i]; i++ )
1668 {
1669 if ( strcmp( node->m_host.h_aliases[i], name ) == 0 )
1670 {
1671 goto exit;
1672 }
1673 }
1674
1675 ret = FALSE;
1676 }
1677
1678 exit:
1679
1680 return ret;
1681 }
1682
1683
1684 //===========================================================================================================================
1685 // HostsFileOpen
1686 //===========================================================================================================================
1687
1688 DEBUG_LOCAL OSStatus
1689 HostsFileOpen( HostsFile ** self, const char * fname )
1690 {
1691 OSStatus err = kNoErr;
1692
1693 *self = (HostsFile*) malloc( sizeof( HostsFile ) );
1694 require_action( *self, exit, err = kNoMemoryErr );
1695 memset( *self, 0, sizeof( HostsFile ) );
1696
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 );
1700
1701 // check malloc
1702
1703 (*self)->m_fp = fopen( fname, "r" );
1704 require_action( (*self)->m_fp, exit, err = kUnknownErr );
1705
1706 exit:
1707
1708 if ( err && *self )
1709 {
1710 HostsFileClose( *self );
1711 *self = NULL;
1712 }
1713
1714 return err;
1715 }
1716
1717
1718 //===========================================================================================================================
1719 // HostsFileClose
1720 //===========================================================================================================================
1721
1722 DEBUG_LOCAL OSStatus
1723 HostsFileClose( HostsFile * self )
1724 {
1725 check( self );
1726
1727 if ( self->m_buffer )
1728 {
1729 free( self->m_buffer );
1730 self->m_buffer = NULL;
1731 }
1732
1733 if ( self->m_fp )
1734 {
1735 fclose( self->m_fp );
1736 self->m_fp = NULL;
1737 }
1738
1739 free( self );
1740
1741 return kNoErr;
1742 }
1743
1744
1745 //===========================================================================================================================
1746 // HostsFileInfoFree
1747 //===========================================================================================================================
1748
1749 DEBUG_LOCAL void
1750 HostsFileInfoFree( HostsFileInfo * info )
1751 {
1752 while ( info )
1753 {
1754 HostsFileInfo * next = info->m_next;
1755
1756 if ( info->m_host.h_addr_list )
1757 {
1758 if ( info->m_host.h_addr_list[0] )
1759 {
1760 free( info->m_host.h_addr_list[0] );
1761 info->m_host.h_addr_list[0] = NULL;
1762 }
1763
1764 free( info->m_host.h_addr_list );
1765 info->m_host.h_addr_list = NULL;
1766 }
1767
1768 if ( info->m_host.h_aliases )
1769 {
1770 int i;
1771
1772 for ( i = 0; info->m_host.h_aliases[i]; i++ )
1773 {
1774 free( info->m_host.h_aliases[i] );
1775 }
1776
1777 free( info->m_host.h_aliases );
1778 }
1779
1780 if ( info->m_host.h_name )
1781 {
1782 free( info->m_host.h_name );
1783 info->m_host.h_name = NULL;
1784 }
1785
1786 free( info );
1787
1788 info = next;
1789 }
1790 }
1791
1792
1793 //===========================================================================================================================
1794 // HostsFileNext
1795 //===========================================================================================================================
1796
1797 DEBUG_LOCAL OSStatus
1798 HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo )
1799 {
1800 struct sockaddr_in6 addr_6;
1801 struct sockaddr_in addr_4;
1802 int numAliases = ALIASES_INITIAL_SIZE;
1803 char * line;
1804 char * tok;
1805 int dwSize;
1806 int idx;
1807 int i;
1808 short family;
1809 OSStatus err = kNoErr;
1810
1811 check( self );
1812 check( self->m_fp );
1813 check( hInfo );
1814
1815 idx = 0;
1816
1817 *hInfo = (HostsFileInfo*) malloc( sizeof( HostsFileInfo ) );
1818 require_action( *hInfo, exit, err = kNoMemoryErr );
1819 memset( *hInfo, 0, sizeof( HostsFileInfo ) );
1820
1821 for ( ; ; )
1822 {
1823 line = fgets( self->m_buffer + idx, self->m_bufferSize - idx, self->m_fp );
1824
1825 if ( line == NULL )
1826 {
1827 err = 1;
1828 goto exit;
1829 }
1830
1831 // If there's no eol and no eof, then we didn't get the whole line
1832
1833 if ( !strchr( line, '\n' ) && !feof( self->m_fp ) )
1834 {
1835 int bufferSize;
1836 char * buffer;
1837
1838 /* Try and allocate space for longer line */
1839
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 );
1846
1847 continue;
1848 }
1849
1850 line = self->m_buffer;
1851 idx = 0;
1852
1853 if (*line == '#')
1854 {
1855 continue;
1856 }
1857
1858 // Get rid of either comments or eol characters
1859
1860 if (( tok = strpbrk(line, "#\n")) != NULL )
1861 {
1862 *tok = '\0';
1863 }
1864
1865 // Make sure there is some whitespace on this line
1866
1867 if (( tok = strpbrk(line, " \t")) == NULL )
1868 {
1869 continue;
1870 }
1871
1872 // Create two strings, where p == the IP Address and tok is the name list
1873
1874 *tok++ = '\0';
1875
1876 while ( *tok == ' ' || *tok == '\t')
1877 {
1878 tok++;
1879 }
1880
1881 // Now we have the name
1882
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 );
1886
1887 // Now create the address (IPv6/IPv4)
1888
1889 addr_6.sin6_family = family = AF_INET6;
1890 dwSize = sizeof( addr_6 );
1891
1892 if ( WSAStringToAddress( line, AF_INET6, NULL, ( struct sockaddr*) &addr_6, &dwSize ) != 0 )
1893 {
1894 addr_4.sin_family = family = AF_INET;
1895 dwSize = sizeof( addr_4 );
1896
1897 if (WSAStringToAddress( line, AF_INET, NULL, ( struct sockaddr*) &addr_4, &dwSize ) != 0 )
1898 {
1899 continue;
1900 }
1901 }
1902
1903 (*hInfo)->m_host.h_addr_list = (char**) malloc( sizeof( char**) * 2 );
1904 require_action( (*hInfo)->m_host.h_addr_list, exit, err = kNoMemoryErr );
1905
1906 if ( family == AF_INET6 )
1907 {
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 ) );
1912
1913 }
1914 else
1915 {
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 ) );
1920 }
1921
1922 (*hInfo)->m_host.h_addr_list[1] = NULL;
1923 (*hInfo)->m_host.h_addrtype = family;
1924
1925 // Now get the aliases
1926
1927 if ((tok = strpbrk(tok, " \t")) != NULL)
1928 {
1929 *tok++ = '\0';
1930 }
1931
1932 i = 0;
1933
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;
1937
1938 while ( tok && *tok )
1939 {
1940 // Skip over the whitespace, waiting for the start of the next alias name
1941
1942 if (*tok == ' ' || *tok == '\t')
1943 {
1944 tok++;
1945 continue;
1946 }
1947
1948 // Check to make sure we don't exhaust the alias buffer
1949
1950 if ( i >= ( numAliases - 1 ) )
1951 {
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 );
1955 }
1956
1957 (*hInfo)->m_host.h_aliases[i] = (char*) malloc( strlen( tok ) + 1 );
1958 require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr );
1959
1960 strcpy( (*hInfo)->m_host.h_aliases[i], tok );
1961
1962 if (( tok = strpbrk( tok, " \t")) != NULL )
1963 {
1964 *tok++ = '\0';
1965 }
1966
1967 (*hInfo)->m_host.h_aliases[++i] = NULL;
1968 }
1969
1970 break;
1971 }
1972
1973 exit:
1974
1975 if ( err && ( *hInfo ) )
1976 {
1977 HostsFileInfoFree( *hInfo );
1978 *hInfo = NULL;
1979 }
1980
1981 return err;
1982 }
1983
1984
1985 //===========================================================================================================================
1986 // GetNextLabel
1987 //===========================================================================================================================
1988 DEBUG_LOCAL const char*
1989 GetNextLabel(const char *cstr, char label[64])
1990 {
1991 char *ptr = label;
1992 while (*cstr && *cstr != '.') // While we have characters in the label...
1993 {
1994 char c = *cstr++;
1995 if (c == '\\')
1996 {
1997 c = *cstr++;
1998 if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
1999 {
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
2005 }
2006 }
2007 *ptr++ = c;
2008 if (ptr >= label+64) return(NULL);
2009 }
2010 if (*cstr) cstr++; // Skip over the trailing dot (if present)
2011 *ptr++ = 0;
2012 return(cstr);
2013 }
2014
2015
2016 #ifdef ENABLE_REVERSE_LOOKUP
2017 //===========================================================================================================================
2018 // IsReverseLookup
2019 //===========================================================================================================================
2020
2021 DEBUG_LOCAL OSStatus
2022 IsReverseLookup( LPCWSTR name, size_t size )
2023 {
2024 LPCWSTR p;
2025 OSStatus err = kNoErr;
2026
2027 require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
2028
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 );
2031
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' ) ) ) )
2049 {
2050 require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
2051
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 );
2054
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 );
2077 }
2078
2079 // It's a reverse lookup
2080
2081 check( err == kNoErr );
2082
2083 exit:
2084
2085 return err;
2086 }
2087 #endif