]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/mdnsNSP/mdnsNSP.c
mDNSResponder-87.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.6 2004/12/06 01:56:53 shersche
27 <rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
28 Bug #: 3789425
29
30 Revision 1.5 2004/07/13 21:24:28 rpantos
31 Fix for <rdar://problem/3701120>.
32
33 Revision 1.4 2004/07/09 18:03:33 shersche
34 removed extraneous DNSServiceQueryRecord call
35
36 Revision 1.3 2004/07/07 17:03:49 shersche
37 <rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
38 Bug #: 3715582
39
40 Revision 1.2 2004/06/24 19:18:07 shersche
41 Rename to mdnsNSP
42 Submitted by: herscher
43
44 Revision 1.1 2004/06/18 04:13:44 rpantos
45 Move up one level.
46
47 Revision 1.2 2004/04/08 09:43:43 bradley
48 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
49
50 Revision 1.1 2004/01/30 03:00:33 bradley
51 mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
52 .local name lookups using Multicast DNS in all Windows apps.
53
54 */
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59
60 #include "CommonServices.h"
61 #include "DebugServices.h"
62
63 #include <guiddef.h>
64 #include <ws2spi.h>
65
66 #include "dns_sd.h"
67
68 #if 0
69 #pragma mark == Structures ==
70 #endif
71
72 //===========================================================================================================================
73 // Structures
74 //===========================================================================================================================
75
76 typedef struct Query * QueryRef;
77 typedef struct Query Query;
78 struct Query
79 {
80 QueryRef next;
81 int refCount;
82 DWORD querySetFlags;
83 WSAQUERYSETW * querySet;
84 size_t querySetSize;
85 HANDLE dataEvent;
86 HANDLE cancelEvent;
87 HANDLE waitHandles[ 2 ];
88 DWORD waitCount;
89 DNSServiceRef resolver;
90 char name[ kDNSServiceMaxDomainName ];
91 size_t nameSize;
92 uint32_t addr;
93 bool addrValid;
94 };
95
96 #if 0
97 #pragma mark == Prototypes ==
98 #endif
99
100 //===========================================================================================================================
101 // Prototypes
102 //===========================================================================================================================
103
104 // DLL Exports
105
106 BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
107
108 // NSP SPIs
109
110 int WSPAPI NSPCleanup( LPGUID inProviderID );
111
112 DEBUG_LOCAL int WSPAPI
113 NSPLookupServiceBegin(
114 LPGUID inProviderID,
115 LPWSAQUERYSETW inQuerySet,
116 LPWSASERVICECLASSINFOW inServiceClassInfo,
117 DWORD inFlags,
118 LPHANDLE outLookup );
119
120 DEBUG_LOCAL int WSPAPI
121 NSPLookupServiceNext(
122 HANDLE inLookup,
123 DWORD inFlags,
124 LPDWORD ioBufferLength,
125 LPWSAQUERYSETW outResults );
126
127 DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup );
128
129 DEBUG_LOCAL int WSPAPI
130 NSPSetService(
131 LPGUID inProviderID,
132 LPWSASERVICECLASSINFOW inServiceClassInfo,
133 LPWSAQUERYSETW inRegInfo,
134 WSAESETSERVICEOP inOperation,
135 DWORD inFlags );
136
137 DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo );
138 DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID );
139 DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioBufSize, LPWSASERVICECLASSINFOW ioServiceClassInfo );
140
141 // Private
142
143 #define NSPLock() EnterCriticalSection( &gLock );
144 #define NSPUnlock() LeaveCriticalSection( &gLock );
145
146 DEBUG_LOCAL OSStatus QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef );
147 DEBUG_LOCAL OSStatus QueryRetain( QueryRef inRef );
148 DEBUG_LOCAL OSStatus QueryRelease( QueryRef inRef );
149
150 DEBUG_LOCAL void CALLBACK_COMPAT
151 QueryRecordCallback(
152 DNSServiceRef inRef,
153 DNSServiceFlags inFlags,
154 uint32_t inInterfaceIndex,
155 DNSServiceErrorType inErrorCode,
156 const char * inName,
157 uint16_t inRRType,
158 uint16_t inRRClass,
159 uint16_t inRDataSize,
160 const void * inRData,
161 uint32_t inTTL,
162 void * inContext );
163
164 DEBUG_LOCAL OSStatus
165 QueryCopyQuerySet(
166 QueryRef inRef,
167 const WSAQUERYSETW * inQuerySet,
168 DWORD inQuerySetFlags,
169 WSAQUERYSETW ** outQuerySet,
170 size_t * outSize );
171
172 DEBUG_LOCAL void
173 QueryCopyQuerySetTo(
174 QueryRef inRef,
175 const WSAQUERYSETW * inQuerySet,
176 DWORD inQuerySetFlags,
177 WSAQUERYSETW * outQuerySet );
178
179 DEBUG_LOCAL size_t QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags );
180
181 #if( DEBUG )
182 void DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet );
183
184 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
185 #else
186 #define dlog_query_set( LEVEL, SET )
187 #endif
188
189 #if 0
190 #pragma mark == Globals ==
191 #endif
192
193 //===========================================================================================================================
194 // Globals
195 //===========================================================================================================================
196
197 // {B600E6E9-553B-4a19-8696-335E5C896153}
198 // GUID kmdnsNSPGUID = { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
199
200 DEBUG_LOCAL LONG gRefCount = 0;
201 DEBUG_LOCAL CRITICAL_SECTION gLock;
202 DEBUG_LOCAL bool gLockInitialized = false;
203 DEBUG_LOCAL bool gDNSSDInitialized = false;
204 DEBUG_LOCAL QueryRef gQueryList = NULL;
205
206 #if 0
207 #pragma mark -
208 #endif
209
210 //===========================================================================================================================
211 // DllMain
212 //===========================================================================================================================
213
214 BOOL APIENTRY DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
215 {
216 DEBUG_USE_ONLY( inInstance );
217 DEBUG_UNUSED( inReserved );
218
219 switch( inReason )
220 {
221 case DLL_PROCESS_ATTACH:
222 debug_initialize( kDebugOutputTypeWindowsEventLog, "mDNS NSP", inInstance );
223 debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
224 dlog( kDebugLevelTrace, "\n" );
225 dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
226 break;
227
228 case DLL_PROCESS_DETACH:
229 dlog( kDebugLevelVerbose, "%s: process detach\n", __ROUTINE__ );
230 break;
231
232 case DLL_THREAD_ATTACH:
233 dlog( kDebugLevelVerbose, "%s: thread attach\n", __ROUTINE__ );
234 break;
235
236 case DLL_THREAD_DETACH:
237 dlog( kDebugLevelVerbose, "%s: thread detach\n", __ROUTINE__ );
238 break;
239
240 default:
241 dlog( kDebugLevelNotice, "%s: unknown reason code (%d)\n", __ROUTINE__, inReason );
242 break;
243 }
244 return( TRUE );
245 }
246
247 //===========================================================================================================================
248 // NSPStartup
249 //
250 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
251 //===========================================================================================================================
252
253 int WSPAPI NSPStartup( LPGUID inProviderID, LPNSP_ROUTINE outRoutines )
254 {
255 OSStatus err;
256
257 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
258 dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
259
260 // Only initialize if this is the first time NSPStartup is called.
261
262 if( InterlockedIncrement( &gRefCount ) != 1 )
263 {
264 err = NO_ERROR;
265 goto exit;
266 }
267
268 // Initialize our internal state.
269
270 InitializeCriticalSection( &gLock );
271 gLockInitialized = true;
272
273 // Set the size to exclude NSPIoctl because we don't implement it.
274
275 outRoutines->cbSize = FIELD_OFFSET( NSP_ROUTINE, NSPIoctl );
276 outRoutines->dwMajorVersion = 4;
277 outRoutines->dwMinorVersion = 4;
278 outRoutines->NSPCleanup = NSPCleanup;
279 outRoutines->NSPLookupServiceBegin = NSPLookupServiceBegin;
280 outRoutines->NSPLookupServiceNext = NSPLookupServiceNext;
281 outRoutines->NSPLookupServiceEnd = NSPLookupServiceEnd;
282 outRoutines->NSPSetService = NSPSetService;
283 outRoutines->NSPInstallServiceClass = NSPInstallServiceClass;
284 outRoutines->NSPRemoveServiceClass = NSPRemoveServiceClass;
285 outRoutines->NSPGetServiceClassInfo = NSPGetServiceClassInfo;
286
287 err = NO_ERROR;
288
289 exit:
290 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
291 if( err != NO_ERROR )
292 {
293 NSPCleanup( inProviderID );
294 SetLastError( (DWORD) err );
295 return( SOCKET_ERROR );
296 }
297 return( NO_ERROR );
298 }
299
300 //===========================================================================================================================
301 // NSPCleanup
302 //
303 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
304 //===========================================================================================================================
305
306 int WSPAPI NSPCleanup( LPGUID inProviderID )
307 {
308 DEBUG_USE_ONLY( inProviderID );
309
310 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
311 dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
312
313 // Only initialize if this is the first time NSPStartup is called.
314
315 if( InterlockedDecrement( &gRefCount ) != 0 )
316 {
317 goto exit;
318 }
319
320 // Stop any outstanding queries.
321
322 if( gLockInitialized )
323 {
324 NSPLock();
325 }
326 while( gQueryList )
327 {
328 check_string( gQueryList->refCount == 1, "NSPCleanup with outstanding queries!" );
329 QueryRelease( gQueryList );
330 }
331 if( gLockInitialized )
332 {
333 NSPUnlock();
334 }
335
336 // Shut down DNS-SD and release our resources.
337
338 if( gDNSSDInitialized )
339 {
340 gDNSSDInitialized = false;
341 }
342 if( gLockInitialized )
343 {
344 gLockInitialized = false;
345 DeleteCriticalSection( &gLock );
346 }
347
348 exit:
349 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
350 return( NO_ERROR );
351 }
352
353 //===========================================================================================================================
354 // NSPLookupServiceBegin
355 //
356 // This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
357 // that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
358 // opposed to specifying the query parameters each time.
359 //===========================================================================================================================
360
361 DEBUG_LOCAL int WSPAPI
362 NSPLookupServiceBegin(
363 LPGUID inProviderID,
364 LPWSAQUERYSETW inQuerySet,
365 LPWSASERVICECLASSINFOW inServiceClassInfo,
366 DWORD inFlags,
367 LPHANDLE outLookup )
368 {
369 OSStatus err;
370 QueryRef obj;
371 LPCWSTR name;
372 size_t size;
373 LPCWSTR p;
374 DWORD type;
375 DWORD n;
376 DWORD i;
377 INT family;
378 INT protocol;
379
380 DEBUG_UNUSED( inProviderID );
381 DEBUG_UNUSED( inServiceClassInfo );
382
383 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
384
385 obj = NULL;
386 require_action( inQuerySet, exit, err = WSAEINVAL );
387 name = inQuerySet->lpszServiceInstanceName;
388 require_action_quiet( name, exit, err = WSAEINVAL );
389 require_action( outLookup, exit, err = WSAEINVAL );
390
391 dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__, inFlags, name );
392 dlog_query_set( kDebugLevelVerbose, inQuerySet );
393
394 // Check if we can handle this type of request and if we support any of the protocols being requested.
395 // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
396
397 require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
398
399 type = inQuerySet->dwNameSpace;
400 require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
401
402 n = inQuerySet->dwNumberOfProtocols;
403 if( n > 0 )
404 {
405 require_action( inQuerySet->lpafpProtocols, exit, err = WSAEINVAL );
406 for( i = 0; i < n; ++i )
407 {
408 family = inQuerySet->lpafpProtocols[ i ].iAddressFamily;
409 protocol = inQuerySet->lpafpProtocols[ i ].iProtocol;
410 if( ( family == AF_INET ) && ( ( protocol == IPPROTO_UDP ) || ( protocol == IPPROTO_TCP ) ) )
411 {
412 break;
413 }
414 }
415 require_action_quiet( i < n, exit, err = WSASERVICE_NOT_FOUND );
416 }
417
418 // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
419 // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
420 // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
421 // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
422 // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
423
424 for( p = name; *p; ++p ) {} // Find end of string
425 size = (size_t)( p - name );
426 require_action_quiet( size > sizeof_string( ".local" ), exit, err = WSASERVICE_NOT_FOUND );
427
428 p = name + ( size - 1 );
429 p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
430 if ( ( ( p[ 0 ] != '.' ) ||
431 ( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) ) ||
432 ( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) ) ||
433 ( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) ) ||
434 ( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) ) ||
435 ( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
436 {
437 require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
438
439 p = name + ( size - 1 );
440 p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
441
442 if ( ( ( p[ 0 ] != '.' ) ||
443 ( ( p[ 1 ] != '0' ) ) ||
444 ( ( p[ 2 ] != '.' ) ) ||
445 ( ( p[ 3 ] != '8' ) ) ||
446 ( ( p[ 4 ] != '.' ) ) ||
447 ( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) ) ||
448 ( ( p[ 6 ] != '.' ) ) ||
449 ( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) ) ||
450 ( ( p[ 8 ] != '.' ) ) ||
451 ( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) ) ||
452 ( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) ) ||
453 ( ( p[ 11 ] != '6' ) ) ||
454 ( ( p[ 12 ] != '.' ) ) ||
455 ( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) ) ||
456 ( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) ) ||
457 ( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) ) ||
458 ( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) )
459 {
460 require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
461
462 p = name + ( size - 1 );
463 p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
464
465 require_action_quiet( ( ( p[ 0 ] == '.' ) &&
466 ( ( p[ 1 ] == '2' ) ) &&
467 ( ( p[ 2 ] == '5' ) ) &&
468 ( ( p[ 3 ] == '4' ) ) &&
469 ( ( p[ 4 ] == '.' ) ) &&
470 ( ( p[ 5 ] == '1' ) ) &&
471 ( ( p[ 6 ] == '6' ) ) &&
472 ( ( p[ 7 ] == '9' ) ) &&
473 ( ( p[ 8 ] == '.' ) ) &&
474 ( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) ) &&
475 ( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) ) &&
476 ( ( p[ 11 ] == '-' ) ) &&
477 ( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) ) &&
478 ( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) ) &&
479 ( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) ) &&
480 ( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) ) &&
481 ( ( p[ 16 ] == '.' ) ) &&
482 ( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) ) &&
483 ( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) ) &&
484 ( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) ) &&
485 ( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ),
486 exit, err = WSASERVICE_NOT_FOUND );
487 }
488 }
489
490 // The name ends in .local, .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
491
492 NSPLock();
493 if( !gDNSSDInitialized )
494 {
495 gDNSSDInitialized = true;
496 }
497
498 err = QueryCreate( inQuerySet, inFlags, &obj );
499 NSPUnlock();
500 require_noerr( err, exit );
501
502 *outLookup = (HANDLE) obj;
503
504 exit:
505 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
506 if( err != NO_ERROR )
507 {
508 SetLastError( (DWORD) err );
509 return( SOCKET_ERROR );
510 }
511 return( NO_ERROR );
512 }
513
514 //===========================================================================================================================
515 // NSPLookupServiceNext
516 //
517 // This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
518 // query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
519 // in the lpqsResults parameter.
520 //===========================================================================================================================
521
522 DEBUG_LOCAL int WSPAPI
523 NSPLookupServiceNext(
524 HANDLE inLookup,
525 DWORD inFlags,
526 LPDWORD ioSize,
527 LPWSAQUERYSETW outResults )
528 {
529 OSStatus err;
530 QueryRef obj;
531 DWORD waitResult;
532 size_t size;
533
534 DEBUG_USE_ONLY( inFlags );
535
536 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
537
538 obj = NULL;
539 NSPLock();
540 err = QueryRetain( (QueryRef) inLookup );
541 require_noerr( err, exit );
542 obj = (QueryRef) inLookup;
543 require_action( ioSize, exit, err = WSAEINVAL );
544 require_action( outResults, exit, err = WSAEINVAL );
545
546 dlog( kDebugLevelTrace, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__, inLookup, inFlags, *ioSize );
547
548 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
549
550 NSPUnlock();
551 waitResult = WaitForMultipleObjects( obj->waitCount, obj->waitHandles, FALSE, 5 * 1000 );
552 NSPLock();
553 require_action_quiet( waitResult != ( WAIT_OBJECT_0 + 1 ), exit, err = WSA_E_CANCELLED );
554 err = translate_errno( waitResult == WAIT_OBJECT_0, (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
555 require_noerr_quiet( err, exit );
556 DNSServiceProcessResult(obj->resolver);
557 require_action_quiet( obj->addrValid, exit, err = WSA_E_NO_MORE );
558
559 // Copy the externalized query results to the callers buffer (if it fits).
560
561 size = QueryCopyQuerySetSize( obj, obj->querySet, obj->querySetFlags );
562 require_action( size <= (size_t) *ioSize, exit, err = WSAEFAULT );
563
564 QueryCopyQuerySetTo( obj, obj->querySet, obj->querySetFlags, outResults );
565 outResults->dwOutputFlags = RESULT_IS_ADDED;
566 obj->addrValid = false;
567
568 exit:
569 if( obj )
570 {
571 QueryRelease( obj );
572 }
573 NSPUnlock();
574 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
575 if( err != NO_ERROR )
576 {
577 SetLastError( (DWORD) err );
578 return( SOCKET_ERROR );
579 }
580 return( NO_ERROR );
581 }
582
583 //===========================================================================================================================
584 // NSPLookupServiceEnd
585 //
586 // This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
587 // indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
588 // allocated resources associated with the query.
589 //===========================================================================================================================
590
591 DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup )
592 {
593 OSStatus err;
594
595 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
596
597 dlog( kDebugLevelTrace, "%s (lookup=%#p)\n", __ROUTINE__, inLookup );
598
599 NSPLock();
600 err = QueryRelease( (QueryRef) inLookup );
601 NSPUnlock();
602 require_noerr( err, exit );
603
604 exit:
605 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
606 if( err != NO_ERROR )
607 {
608 SetLastError( (DWORD) err );
609 return( SOCKET_ERROR );
610 }
611 return( NO_ERROR );
612 }
613
614 //===========================================================================================================================
615 // NSPSetService
616 //
617 // This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
618 // deregister an instance of a server with our service. For registration, the user needs to associate the server with a
619 // service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
620 // contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
621 //===========================================================================================================================
622
623 DEBUG_LOCAL int WSPAPI
624 NSPSetService(
625 LPGUID inProviderID,
626 LPWSASERVICECLASSINFOW inServiceClassInfo,
627 LPWSAQUERYSETW inRegInfo,
628 WSAESETSERVICEOP inOperation,
629 DWORD inFlags )
630 {
631 DEBUG_UNUSED( inProviderID );
632 DEBUG_UNUSED( inServiceClassInfo );
633 DEBUG_UNUSED( inRegInfo );
634 DEBUG_UNUSED( inOperation );
635 DEBUG_UNUSED( inFlags );
636
637 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
638 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
639
640 // We don't allow services to be registered so always return an error.
641
642 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
643 return( WSAEINVAL );
644 }
645
646 //===========================================================================================================================
647 // NSPInstallServiceClass
648 //
649 // This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
650 // is used to define certain characteristics for a group of services. After a service class is registered, an actual
651 // instance of a server may be registered.
652 //===========================================================================================================================
653
654 DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo )
655 {
656 DEBUG_UNUSED( inProviderID );
657 DEBUG_UNUSED( inServiceClassInfo );
658
659 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
660 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
661
662 // We don't allow service classes to be installed so always return an error.
663
664 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
665 return( WSA_INVALID_PARAMETER );
666 }
667
668 //===========================================================================================================================
669 // NSPRemoveServiceClass
670 //
671 // This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
672 // class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
673 // service class.
674 //===========================================================================================================================
675
676 DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID )
677 {
678 DEBUG_UNUSED( inProviderID );
679 DEBUG_UNUSED( inServiceClassID );
680
681 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
682 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
683
684 // We don't allow service classes to be installed so always return an error.
685
686 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
687 return( WSATYPE_NOT_FOUND );
688 }
689
690 //===========================================================================================================================
691 // NSPGetServiceClassInfo
692 //
693 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
694 // a given service class.
695 //===========================================================================================================================
696
697 DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioSize, LPWSASERVICECLASSINFOW ioServiceClassInfo )
698 {
699 DEBUG_UNUSED( inProviderID );
700 DEBUG_UNUSED( ioSize );
701 DEBUG_UNUSED( ioServiceClassInfo );
702
703 dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
704 dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
705
706 // We don't allow service classes to be installed so always return an error.
707
708 dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
709 return( WSATYPE_NOT_FOUND );
710 }
711
712 #if 0
713 #pragma mark -
714 #endif
715
716 //===========================================================================================================================
717 // QueryCreate
718 //
719 // Warning: Assumes the NSP lock is held.
720 //===========================================================================================================================
721
722 DEBUG_LOCAL OSStatus QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef )
723 {
724 OSStatus err;
725 QueryRef obj;
726 char name[ kDNSServiceMaxDomainName ];
727 int n;
728 QueryRef * p;
729
730 obj = NULL;
731 check( inQuerySet );
732 check( inQuerySet->lpszServiceInstanceName );
733 check( outRef );
734
735 // Convert the wchar_t name to UTF-8.
736
737 n = WideCharToMultiByte( CP_UTF8, 0, inQuerySet->lpszServiceInstanceName, -1, name, sizeof( name ), NULL, NULL );
738 err = translate_errno( n > 0, (OSStatus) GetLastError(), WSAEINVAL );
739 require_noerr( err, exit );
740
741 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
742
743 obj = (QueryRef) calloc( 1, sizeof( *obj ) );
744 require_action( obj, exit, err = WSA_NOT_ENOUGH_MEMORY );
745
746 obj->refCount = 1;
747
748 for( p = &gQueryList; *p; p = &( *p )->next ) {} // Find the end of the list.
749 *p = obj;
750
751 // Set up events to signal when data is ready and when cancelling.
752
753 obj->dataEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
754 require_action( obj->dataEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
755
756 obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
757 require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
758
759 // Start the query.
760
761 err = DNSServiceQueryRecord( &obj->resolver, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN,
762 QueryRecordCallback, obj );
763 require_noerr( err, exit );
764
765 // Attach the socket to the event
766
767 WSAEventSelect(DNSServiceRefSockFD(obj->resolver), obj->dataEvent, FD_READ|FD_CLOSE);
768
769 obj->waitCount = 0;
770 obj->waitHandles[ obj->waitCount++ ] = obj->dataEvent;
771 obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
772 check( obj->waitCount == sizeof_array( obj->waitHandles ) );
773
774 // Copy the QuerySet so it can be returned later.
775
776 obj->querySetFlags = inQuerySetFlags;
777 inQuerySetFlags = ( inQuerySetFlags & ~( LUP_RETURN_ADDR | LUP_RETURN_BLOB ) ) | LUP_RETURN_NAME;
778 err = QueryCopyQuerySet( obj, inQuerySet, inQuerySetFlags, &obj->querySet, &obj->querySetSize );
779 require_noerr( err, exit );
780
781 // Success!
782
783 *outRef = obj;
784 obj = NULL;
785 err = NO_ERROR;
786
787 exit:
788 if( obj )
789 {
790 QueryRelease( obj );
791 }
792 return( err );
793 }
794
795 //===========================================================================================================================
796 // QueryRetain
797 //
798 // Warning: Assumes the NSP lock is held.
799 //===========================================================================================================================
800
801 DEBUG_LOCAL OSStatus QueryRetain( QueryRef inRef )
802 {
803 OSStatus err;
804 QueryRef obj;
805
806 for( obj = gQueryList; obj; obj = obj->next )
807 {
808 if( obj == inRef )
809 {
810 break;
811 }
812 }
813 require_action( obj, exit, err = WSA_INVALID_HANDLE );
814
815 ++inRef->refCount;
816 err = NO_ERROR;
817
818 exit:
819 return( err );
820 }
821
822 //===========================================================================================================================
823 // QueryRelease
824 //
825 // Warning: Assumes the NSP lock is held.
826 //===========================================================================================================================
827
828 DEBUG_LOCAL OSStatus QueryRelease( QueryRef inRef )
829 {
830 OSStatus err;
831 QueryRef * p;
832 BOOL ok;
833
834 // Find the item in the list.
835
836 for( p = &gQueryList; *p; p = &( *p )->next )
837 {
838 if( *p == inRef )
839 {
840 break;
841 }
842 }
843 require_action( *p, exit, err = WSA_INVALID_HANDLE );
844
845 // Signal a cancel to unblock any threads waiting for results.
846
847 if( inRef->cancelEvent )
848 {
849 ok = SetEvent( inRef->cancelEvent );
850 check_translated_errno( ok, GetLastError(), WSAEINVAL );
851 }
852
853 // Stop the query.
854
855 if( inRef->resolver )
856 {
857 DNSServiceRefDeallocate( inRef->resolver );
858 inRef->resolver = NULL;
859 }
860
861 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
862
863 if( --inRef->refCount != 0 )
864 {
865 err = NO_ERROR;
866 goto exit;
867 }
868 *p = inRef->next;
869
870 // Release resources.
871
872 if( inRef->cancelEvent )
873 {
874 ok = CloseHandle( inRef->cancelEvent );
875 check_translated_errno( ok, GetLastError(), WSAEINVAL );
876 }
877 if( inRef->dataEvent )
878 {
879 ok = CloseHandle( inRef->dataEvent );
880 check_translated_errno( ok, GetLastError(), WSAEINVAL );
881 }
882 if( inRef->querySet )
883 {
884 free( inRef->querySet );
885 }
886 free( inRef );
887 err = NO_ERROR;
888
889 exit:
890 return( err );
891 }
892
893 //===========================================================================================================================
894 // QueryRecordCallback
895 //===========================================================================================================================
896
897 DEBUG_LOCAL void CALLBACK_COMPAT
898 QueryRecordCallback(
899 DNSServiceRef inRef,
900 DNSServiceFlags inFlags,
901 uint32_t inInterfaceIndex,
902 DNSServiceErrorType inErrorCode,
903 const char * inName,
904 uint16_t inRRType,
905 uint16_t inRRClass,
906 uint16_t inRDataSize,
907 const void * inRData,
908 uint32_t inTTL,
909 void * inContext )
910 {
911 QueryRef obj;
912 const char * src;
913 char * dst;
914 BOOL ok;
915
916 DEBUG_UNUSED( inFlags );
917 DEBUG_UNUSED( inInterfaceIndex );
918 DEBUG_UNUSED( inTTL );
919
920 NSPLock();
921 obj = (QueryRef) inContext;
922 check( obj );
923 require_noerr( inErrorCode, exit );
924 require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
925 require( inRRClass == kDNSServiceClass_IN, exit );
926 require( inRRType == kDNSServiceType_A, exit );
927 require( inRDataSize == 4, exit );
928
929 dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
930 __ROUTINE__, inFlags, inName, inRRType, inRDataSize );
931
932 // Copy the name if needed.
933
934 if( obj->name[ 0 ] == '\0' )
935 {
936 src = inName;
937 dst = obj->name;
938 while( *src != '\0' )
939 {
940 *dst++ = *src++;
941 }
942 *dst = '\0';
943 obj->nameSize = (size_t)( dst - obj->name );
944 check( obj->nameSize < sizeof( obj->name ) );
945 }
946
947 // Copy the data.
948
949 memcpy( &obj->addr, inRData, inRDataSize );
950 obj->addrValid = true;
951
952 // Signal that a result is ready.
953
954 check( obj->dataEvent );
955 ok = SetEvent( obj->dataEvent );
956 check_translated_errno( ok, GetLastError(), WSAEINVAL );
957
958 // Stop the resolver after the first response.
959
960 DNSServiceRefDeallocate( inRef );
961 obj->resolver = NULL;
962
963 exit:
964 NSPUnlock();
965 }
966
967 #if 0
968 #pragma mark -
969 #endif
970
971 //===========================================================================================================================
972 // QueryCopyQuerySet
973 //
974 // Warning: Assumes the NSP lock is held.
975 //===========================================================================================================================
976
977 DEBUG_LOCAL OSStatus
978 QueryCopyQuerySet(
979 QueryRef inRef,
980 const WSAQUERYSETW * inQuerySet,
981 DWORD inQuerySetFlags,
982 WSAQUERYSETW ** outQuerySet,
983 size_t * outSize )
984 {
985 OSStatus err;
986 size_t size;
987 WSAQUERYSETW * qs;
988
989 check( inQuerySet );
990 check( outQuerySet );
991
992 size = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
993 qs = (WSAQUERYSETW *) calloc( 1, size );
994 require_action( qs, exit, err = WSA_NOT_ENOUGH_MEMORY );
995
996 QueryCopyQuerySetTo( inRef, inQuerySet, inQuerySetFlags, qs );
997
998 *outQuerySet = qs;
999 if( outSize )
1000 {
1001 *outSize = size;
1002 }
1003 qs = NULL;
1004 err = NO_ERROR;
1005
1006 exit:
1007 if( qs )
1008 {
1009 free( qs );
1010 }
1011 return( err );
1012 }
1013
1014 //===========================================================================================================================
1015 // QueryCopyQuerySetTo
1016 //
1017 // Warning: Assumes the NSP lock is held.
1018 //===========================================================================================================================
1019
1020 DEBUG_LOCAL void
1021 QueryCopyQuerySetTo(
1022 QueryRef inRef,
1023 const WSAQUERYSETW * inQuerySet,
1024 DWORD inQuerySetFlags,
1025 WSAQUERYSETW * outQuerySet )
1026 {
1027 uint8_t * dst;
1028 LPCWSTR s;
1029 LPWSTR q;
1030 DWORD n;
1031 DWORD i;
1032
1033 #if( DEBUG )
1034 size_t debugSize;
1035
1036 debugSize = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
1037 #endif
1038
1039 check( inQuerySet );
1040 check( outQuerySet );
1041
1042 dst = (uint8_t *) outQuerySet;
1043
1044 // Copy the static portion of the results.
1045
1046 *outQuerySet = *inQuerySet;
1047 dst += sizeof( *inQuerySet );
1048
1049 if( inQuerySetFlags & LUP_RETURN_NAME )
1050 {
1051 s = inQuerySet->lpszServiceInstanceName;
1052 if( s )
1053 {
1054 outQuerySet->lpszServiceInstanceName = (LPWSTR) dst;
1055 q = (LPWSTR) dst;
1056 while( ( *q++ = *s++ ) != 0 ) {}
1057 dst = (uint8_t *) q;
1058 }
1059 }
1060 else
1061 {
1062 outQuerySet->lpszServiceInstanceName = NULL;
1063 }
1064
1065 if( inQuerySet->lpServiceClassId )
1066 {
1067 outQuerySet->lpServiceClassId = (LPGUID) dst;
1068 *outQuerySet->lpServiceClassId = *inQuerySet->lpServiceClassId;
1069 dst += sizeof( *inQuerySet->lpServiceClassId );
1070 }
1071
1072 if( inQuerySet->lpVersion )
1073 {
1074 outQuerySet->lpVersion = (LPWSAVERSION) dst;
1075 *outQuerySet->lpVersion = *inQuerySet->lpVersion;
1076 dst += sizeof( *inQuerySet->lpVersion );
1077 }
1078
1079 s = inQuerySet->lpszComment;
1080 if( s )
1081 {
1082 outQuerySet->lpszComment = (LPWSTR) dst;
1083 q = (LPWSTR) dst;
1084 while( ( *q++ = *s++ ) != 0 ) {}
1085 dst = (uint8_t *) q;
1086 }
1087
1088 if( inQuerySet->lpNSProviderId )
1089 {
1090 outQuerySet->lpNSProviderId = (LPGUID) dst;
1091 *outQuerySet->lpNSProviderId = *inQuerySet->lpNSProviderId;
1092 dst += sizeof( *inQuerySet->lpNSProviderId );
1093 }
1094
1095 s = inQuerySet->lpszContext;
1096 if( s )
1097 {
1098 outQuerySet->lpszContext = (LPWSTR) dst;
1099 q = (LPWSTR) dst;
1100 while( ( *q++ = *s++ ) != 0 ) {}
1101 dst = (uint8_t *) q;
1102 }
1103
1104 n = inQuerySet->dwNumberOfProtocols;
1105 if( n > 0 )
1106 {
1107 check( inQuerySet->lpafpProtocols );
1108
1109 outQuerySet->lpafpProtocols = (LPAFPROTOCOLS) dst;
1110 for( i = 0; i < n; ++i )
1111 {
1112 outQuerySet->lpafpProtocols[ i ] = inQuerySet->lpafpProtocols[ i ];
1113 dst += sizeof( *inQuerySet->lpafpProtocols );
1114 }
1115 }
1116
1117 s = inQuerySet->lpszQueryString;
1118 if( s )
1119 {
1120 outQuerySet->lpszQueryString = (LPWSTR) dst;
1121 q = (LPWSTR) dst;
1122 while( ( *q++ = *s++ ) != 0 ) {}
1123 dst = (uint8_t *) q;
1124 }
1125
1126 // Copy the address(es).
1127
1128 if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addrValid )
1129 {
1130 struct sockaddr_in * addr;
1131
1132 outQuerySet->dwNumberOfCsAddrs = 1;
1133 outQuerySet->lpcsaBuffer = (LPCSADDR_INFO) dst;
1134 dst += sizeof( *outQuerySet->lpcsaBuffer );
1135
1136 outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.lpSockaddr = NULL;
1137 outQuerySet->lpcsaBuffer[ 0 ].LocalAddr.iSockaddrLength = 0;
1138
1139 outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.lpSockaddr = (LPSOCKADDR) dst;
1140 outQuerySet->lpcsaBuffer[ 0 ].RemoteAddr.iSockaddrLength = sizeof( struct sockaddr_in );
1141
1142 addr = (struct sockaddr_in *) dst;
1143 memset( addr, 0, sizeof( *addr ) );
1144 addr->sin_family = AF_INET;
1145 memcpy( &addr->sin_addr, &inRef->addr, 4 );
1146 dst += sizeof( *addr );
1147
1148 outQuerySet->lpcsaBuffer[ 0 ].iSocketType = AF_INET; // Emulate Tcpip NSP
1149 outQuerySet->lpcsaBuffer[ 0 ].iProtocol = IPPROTO_UDP; // Emulate Tcpip NSP
1150 }
1151 else
1152 {
1153 outQuerySet->dwNumberOfCsAddrs = 0;
1154 outQuerySet->lpcsaBuffer = NULL;
1155 }
1156
1157 // Copy the hostent blob.
1158
1159 if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
1160 {
1161 uint8_t * base;
1162 struct hostent * he;
1163 uintptr_t * p;
1164
1165 outQuerySet->lpBlob = (LPBLOB) dst;
1166 dst += sizeof( *outQuerySet->lpBlob );
1167
1168 base = dst;
1169 he = (struct hostent *) dst;
1170 dst += sizeof( *he );
1171
1172 he->h_name = (char *)( dst - base );
1173 memcpy( dst, inRef->name, inRef->nameSize + 1 );
1174 dst += ( inRef->nameSize + 1 );
1175
1176 he->h_aliases = (char **)( dst - base );
1177 p = (uintptr_t *) dst;
1178 *p++ = 0;
1179 dst = (uint8_t *) p;
1180
1181 he->h_addrtype = AF_INET;
1182 he->h_length = 4;
1183
1184 he->h_addr_list = (char **)( dst - base );
1185 p = (uintptr_t *) dst;
1186 dst += ( 2 * sizeof( *p ) );
1187 *p++ = (uintptr_t)( dst - base );
1188 *p++ = 0;
1189 p = (uintptr_t *) dst;
1190 *p++ = (uintptr_t) inRef->addr;
1191 dst = (uint8_t *) p;
1192
1193 outQuerySet->lpBlob->cbSize = (ULONG)( dst - base );
1194 outQuerySet->lpBlob->pBlobData = (BYTE *) base;
1195 }
1196 dlog_query_set( kDebugLevelVerbose, outQuerySet );
1197
1198 check( (size_t)( dst - ( (uint8_t *) outQuerySet ) ) == debugSize );
1199 }
1200
1201 //===========================================================================================================================
1202 // QueryCopyQuerySetSize
1203 //
1204 // Warning: Assumes the NSP lock is held.
1205 //===========================================================================================================================
1206
1207 DEBUG_LOCAL size_t QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags )
1208 {
1209 size_t size;
1210 LPCWSTR s;
1211 LPCWSTR p;
1212
1213 check( inRef );
1214 check( inQuerySet );
1215
1216 // Calculate the size of the static portion of the results.
1217
1218 size = sizeof( *inQuerySet );
1219
1220 if( inQuerySetFlags & LUP_RETURN_NAME )
1221 {
1222 s = inQuerySet->lpszServiceInstanceName;
1223 if( s )
1224 {
1225 for( p = s; *p; ++p ) {}
1226 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1227 }
1228 }
1229
1230 if( inQuerySet->lpServiceClassId )
1231 {
1232 size += sizeof( *inQuerySet->lpServiceClassId );
1233 }
1234
1235 if( inQuerySet->lpVersion )
1236 {
1237 size += sizeof( *inQuerySet->lpVersion );
1238 }
1239
1240 s = inQuerySet->lpszComment;
1241 if( s )
1242 {
1243 for( p = s; *p; ++p ) {}
1244 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1245 }
1246
1247 if( inQuerySet->lpNSProviderId )
1248 {
1249 size += sizeof( *inQuerySet->lpNSProviderId );
1250 }
1251
1252 s = inQuerySet->lpszContext;
1253 if( s )
1254 {
1255 for( p = s; *p; ++p ) {}
1256 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1257 }
1258
1259 size += ( inQuerySet->dwNumberOfProtocols * sizeof( *inQuerySet->lpafpProtocols ) );
1260
1261 s = inQuerySet->lpszQueryString;
1262 if( s )
1263 {
1264 for( p = s; *p; ++p ) {}
1265 size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1266 }
1267
1268 // Calculate the size of the address(es).
1269
1270 if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addrValid )
1271 {
1272 size += sizeof( *inQuerySet->lpcsaBuffer );
1273 size += sizeof( struct sockaddr_in );
1274 }
1275
1276 // Calculate the size of the hostent blob.
1277
1278 if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addrValid )
1279 {
1280 size += sizeof( *inQuerySet->lpBlob ); // Blob ptr/size structure
1281 size += sizeof( struct hostent ); // Old-style hostent structure
1282 size += ( inRef->nameSize + 1 ); // Name and null terminator
1283 size += 4; // Alias list terminator (0 offset)
1284 size += 4; // Offset to address.
1285 size += 4; // Address list terminator (0 offset)
1286 size += 4; // IPv4 address
1287 }
1288 return( size );
1289 }
1290
1291 #if 0
1292 #pragma mark -
1293 #endif
1294
1295 #if( DEBUG )
1296 //===========================================================================================================================
1297 // DebugDumpQuerySet
1298 //===========================================================================================================================
1299
1300 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1301 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1302
1303 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1304 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1305
1306 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1307
1308 void DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet )
1309 {
1310 DWORD i;
1311
1312 check( inQuerySet );
1313
1314 // Fixed portion of the QuerySet.
1315
1316 dlog( inLevel, "QuerySet:\n" );
1317 dlog( inLevel, " dwSize: %d (expected %d)\n", inQuerySet->dwSize, sizeof( *inQuerySet ) );
1318 if( inQuerySet->lpszServiceInstanceName )
1319 {
1320 dlog( inLevel, " lpszServiceInstanceName: %S\n", inQuerySet->lpszServiceInstanceName );
1321 }
1322 else
1323 {
1324 dlog( inLevel, " lpszServiceInstanceName: <null>\n" );
1325 }
1326 if( inQuerySet->lpServiceClassId )
1327 {
1328 dlog( inLevel, " lpServiceClassId: %U\n", inQuerySet->lpServiceClassId );
1329 }
1330 else
1331 {
1332 dlog( inLevel, " lpServiceClassId: <null>\n" );
1333 }
1334 if( inQuerySet->lpVersion )
1335 {
1336 dlog( inLevel, " lpVersion:\n" );
1337 dlog( inLevel, " dwVersion: %d\n", inQuerySet->lpVersion->dwVersion );
1338 dlog( inLevel, " dwVersion: %d\n", inQuerySet->lpVersion->ecHow );
1339 }
1340 else
1341 {
1342 dlog( inLevel, " lpVersion: <null>\n" );
1343 }
1344 if( inQuerySet->lpszComment )
1345 {
1346 dlog( inLevel, " lpszComment: %S\n", inQuerySet->lpszComment );
1347 }
1348 else
1349 {
1350 dlog( inLevel, " lpszComment: <null>\n" );
1351 }
1352 dlog( inLevel, " dwNameSpace: %d %s\n", inQuerySet->dwNameSpace,
1353 DebugNameSpaceToString( inQuerySet->dwNameSpace ) );
1354 if( inQuerySet->lpNSProviderId )
1355 {
1356 dlog( inLevel, " lpNSProviderId: %U\n", inQuerySet->lpNSProviderId );
1357 }
1358 else
1359 {
1360 dlog( inLevel, " lpNSProviderId: <null>\n" );
1361 }
1362 if( inQuerySet->lpszContext )
1363 {
1364 dlog( inLevel, " lpszContext: %S\n", inQuerySet->lpszContext );
1365 }
1366 else
1367 {
1368 dlog( inLevel, " lpszContext: <null>\n" );
1369 }
1370 dlog( inLevel, " dwNumberOfProtocols: %d\n", inQuerySet->dwNumberOfProtocols );
1371 dlog( inLevel, " lpafpProtocols: %s\n", inQuerySet->lpafpProtocols ? "" : "<null>" );
1372 for( i = 0; i < inQuerySet->dwNumberOfProtocols; ++i )
1373 {
1374 if( i != 0 )
1375 {
1376 dlog( inLevel, "\n" );
1377 }
1378 dlog( inLevel, " iAddressFamily: %d %s\n", inQuerySet->lpafpProtocols[ i ].iAddressFamily,
1379 DebugSocketFamilyToString( inQuerySet->lpafpProtocols[ i ].iAddressFamily ) );
1380 dlog( inLevel, " iProtocol: %d %s\n", inQuerySet->lpafpProtocols[ i ].iProtocol,
1381 DebugSocketProtocolToString( inQuerySet->lpafpProtocols[ i ].iProtocol ) );
1382 }
1383 if( inQuerySet->lpszQueryString )
1384 {
1385 dlog( inLevel, " lpszQueryString: %S\n", inQuerySet->lpszQueryString );
1386 }
1387 else
1388 {
1389 dlog( inLevel, " lpszQueryString: <null>\n" );
1390 }
1391 dlog( inLevel, " dwNumberOfCsAddrs: %d\n", inQuerySet->dwNumberOfCsAddrs );
1392 dlog( inLevel, " lpcsaBuffer: %s\n", inQuerySet->lpcsaBuffer ? "" : "<null>" );
1393 for( i = 0; i < inQuerySet->dwNumberOfCsAddrs; ++i )
1394 {
1395 if( i != 0 )
1396 {
1397 dlog( inLevel, "\n" );
1398 }
1399 if( inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr &&
1400 ( inQuerySet->lpcsaBuffer[ i ].LocalAddr.iSockaddrLength > 0 ) )
1401 {
1402 dlog( inLevel, " LocalAddr: %##a\n",
1403 inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr );
1404 }
1405 else
1406 {
1407 dlog( inLevel, " LocalAddr: <null/empty>\n" );
1408 }
1409 if( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr &&
1410 ( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.iSockaddrLength > 0 ) )
1411 {
1412 dlog( inLevel, " RemoteAddr: %##a\n",
1413 inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr );
1414 }
1415 else
1416 {
1417 dlog( inLevel, " RemoteAddr: <null/empty>\n" );
1418 }
1419 dlog( inLevel, " iSocketType: %d\n", inQuerySet->lpcsaBuffer[ i ].iSocketType );
1420 dlog( inLevel, " iProtocol: %d\n", inQuerySet->lpcsaBuffer[ i ].iProtocol );
1421 }
1422 dlog( inLevel, " dwOutputFlags: %d\n", inQuerySet->dwOutputFlags );
1423
1424 // Blob portion of the QuerySet.
1425
1426 if( inQuerySet->lpBlob )
1427 {
1428 dlog( inLevel, " lpBlob:\n" );
1429 dlog( inLevel, " cbSize: %ld\n", inQuerySet->lpBlob->cbSize );
1430 dlog( inLevel, " pBlobData: %#p\n", inQuerySet->lpBlob->pBlobData );
1431 dloghex( inLevel, 12, NULL, 0, 0, NULL, 0,
1432 inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->cbSize,
1433 kDebugFlagsNone, NULL, 0 );
1434 }
1435 else
1436 {
1437 dlog( inLevel, " lpBlob: <null>\n" );
1438 }
1439 }
1440 #endif