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