blob: 0dcc1217a562007188ce4ad84e2496b73fc98e4f [file] [log] [blame]
Casey Dahlin3dfdc952016-07-19 13:54:29 -07001/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17 To Do:
18
19 - Get unicode name of machine for nice name instead of just the host name.
20 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
21 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
22 - Implement TCP support for truncated packets (only stubs now).
23
24*/
25
26#include <stdarg.h>
27#include <stddef.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <crtdbg.h>
31#include <string.h>
32
33#include "CommonServices.h"
34#include "DebugServices.h"
35#include "Firewall.h"
36#include "RegNames.h"
37#include "Secret.h"
38#include <dns_sd.h>
39
40#include <Iphlpapi.h>
41#include <mswsock.h>
42#include <process.h>
43#include <ntsecapi.h>
44#include <lm.h>
45#include <winioctl.h>
46#include <ntddndis.h> // This defines the IOCTL constants.
47
48#include "mDNSEmbeddedAPI.h"
49#include "GenLinkedList.h"
50#include "DNSCommon.h"
51#include "mDNSWin32.h"
52
53#if 0
54#pragma mark == Constants ==
55#endif
56
57//===========================================================================================================================
58// Constants
59//===========================================================================================================================
60
61#define DEBUG_NAME "[mDNSWin32] "
62
63#define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
64#define MDNS_WINDOWS_ENABLE_IPV4 1
65#define MDNS_WINDOWS_ENABLE_IPV6 1
66#define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
67#define MDNS_SET_HINFO_STRINGS 0
68
69#define kMDNSDefaultName "My Computer"
70
71#define kWinSockMajorMin 2
72#define kWinSockMinorMin 2
73
74#define kRegistryMaxKeyLength 255
75#define kRegistryMaxValueName 16383
76
77static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
78
79#define kIPv6IfIndexBase (10000000L)
80#define SMBPortAsNumber 445
81#define DEVICE_PREFIX "\\\\.\\"
82
83#if 0
84#pragma mark == Prototypes ==
85#endif
86
87//===========================================================================================================================
88// Prototypes
89//===========================================================================================================================
90
91mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS );
92mDNSlocal mStatus SetupHostName( mDNS * const inMDNS );
93mDNSlocal mStatus SetupName( mDNS * const inMDNS );
94mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
95mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
96mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD );
97mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef );
98mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
99mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
100mDNSlocal int getifaddrs( struct ifaddrs **outAddrs );
101mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs );
102
103
104
105// Platform Accessors
106
107#ifdef __cplusplus
108 extern "C" {
109#endif
110
111typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
112struct mDNSPlatformInterfaceInfo
113{
114 const char * name;
115 mDNSAddr ip;
116};
117
118
119mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
120mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
121
122// Utilities
123
124#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
125 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
126#endif
127
128mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
129
130
131mDNSlocal DWORD GetPrimaryInterface();
132mDNSlocal mStatus AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
133mDNSlocal mDNSBool CanReceiveUnicast( void );
134mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
135
136mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string );
137mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
138mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh);
139mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
140mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
141mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context );
142mDNSlocal void TCPCanRead( TCPSocket * sock );
143mDNSlocal mStatus TCPBeginRecv( TCPSocket * sock );
144mDNSlocal void CALLBACK TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
145mDNSlocal void TCPCloseSocket( TCPSocket * socket );
146mDNSlocal void CALLBACK TCPFreeSocket( TCPSocket *sock );
147mDNSlocal OSStatus UDPBeginRecv( UDPSocket * socket );
148mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
149mDNSlocal void UDPCloseSocket( UDPSocket * sock );
150mDNSlocal void CALLBACK UDPFreeSocket( UDPSocket * sock );
151mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
152mDNSlocal void GetDDNSFQDN( domainname *const fqdn );
153#ifdef UNICODE
154mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
155#else
156mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
157#endif
158mDNSlocal void SetDomainSecrets( mDNS * const inMDNS );
159mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain );
160mDNSlocal VOID CALLBACK CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
161mDNSlocal void CheckFileShares( mDNS * const inMDNS );
162mDNSlocal void SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
163mDNSlocal mDNSu8 IsWOMPEnabledForAdapter( const char * adapterName );
164mDNSlocal void DispatchUDPEvent( mDNS * const m, UDPSocket * sock );
165mDNSlocal void DispatchTCPEvent( mDNS * const m, TCPSocket * sock );
166
167#ifdef __cplusplus
168 }
169#endif
170
171#if 0
172#pragma mark == Globals ==
173#endif
174
175//===========================================================================================================================
176// Globals
177//===========================================================================================================================
178
179mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
180mDNSs32 mDNSPlatformOneSecond = 0;
181mDNSlocal UDPSocket * gUDPSockets = NULL;
182mDNSlocal int gUDPNumSockets = 0;
183mDNSlocal GenLinkedList gUDPDispatchableSockets;
184mDNSlocal GenLinkedList gTCPDispatchableSockets;
185
186#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
187
188 typedef DWORD
189 ( WINAPI * GetAdaptersAddressesFunctionPtr )(
190 ULONG inFamily,
191 DWORD inFlags,
192 PVOID inReserved,
193 PIP_ADAPTER_ADDRESSES inAdapter,
194 PULONG outBufferSize );
195
196 mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
197 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
198
199#endif
200
201
202#ifndef HCRYPTPROV
203 typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249
204#endif
205
206
207#ifndef CRYPT_MACHINE_KEYSET
208# define CRYPT_MACHINE_KEYSET 0x00000020
209#endif
210
211#ifndef CRYPT_NEWKEYSET
212# define CRYPT_NEWKEYSET 0x00000008
213#endif
214
215#ifndef PROV_RSA_FULL
216# define PROV_RSA_FULL 1
217#endif
218
219typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
220typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
221typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
222
223static fnCryptAcquireContext g_lpCryptAcquireContext = NULL;
224static fnCryptReleaseContext g_lpCryptReleaseContext = NULL;
225static fnCryptGenRandom g_lpCryptGenRandom = NULL;
226static HINSTANCE g_hAAPI32 = NULL;
227static HCRYPTPROV g_hProvider = ( ULONG_PTR ) NULL;
228
229
230typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
231 (
232 DNSServiceRef *sdRef,
233 DNSServiceFlags flags,
234 uint32_t interfaceIndex,
235 const char *name, /* may be NULL */
236 const char *regtype,
237 const char *domain, /* may be NULL */
238 const char *host, /* may be NULL */
239 uint16_t port,
240 uint16_t txtLen,
241 const void *txtRecord, /* may be NULL */
242 DNSServiceRegisterReply callBack, /* may be NULL */
243 void *context /* may be NULL */
244 );
245
246
247typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
248
249mDNSlocal HMODULE gDNSSDLibrary = NULL;
250mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister = NULL;
251mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
252mDNSlocal HANDLE gSMBThread = NULL;
253mDNSlocal HANDLE gSMBThreadRegisterEvent = NULL;
254mDNSlocal HANDLE gSMBThreadDeregisterEvent = NULL;
255mDNSlocal HANDLE gSMBThreadStopEvent = NULL;
256mDNSlocal HANDLE gSMBThreadQuitEvent = NULL;
257
258#define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
259#define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
260#define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
261
262
263#if 0
264#pragma mark -
265#pragma mark == Platform Support ==
266#endif
267
268//===========================================================================================================================
269// mDNSPlatformInit
270//===========================================================================================================================
271
272mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
273{
274 mStatus err;
275 WSADATA wsaData;
276 int supported;
277 struct sockaddr_in sa4;
278 struct sockaddr_in6 sa6;
279 int sa4len;
280 int sa6len;
281 DWORD size;
282 DWORD val;
283
284 dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
285
286 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
287 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
288
289 mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
290 if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
291 inMDNS->p->mainThread = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
292 require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
293 inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
294 require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
295 inMDNS->p->checkFileSharesTimeout = 10; // Retry time for CheckFileShares() in seconds
296 mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
297 InitLinkedList( &gTCPDispatchableSockets, offsetof( TCPSocket, nextDispatchable ) );
298 InitLinkedList( &gUDPDispatchableSockets, offsetof( UDPSocket, nextDispatchable ) );
299
300 // Startup WinSock 2.2 or later.
301
302 err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
303 require_noerr( err, exit );
304
305 supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
306 require_action( supported, exit, err = mStatus_UnsupportedErr );
307
308 inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
309
310 // Setup the HINFO HW strings.
311 //<rdar://problem/7245119> device-info should have model=Windows
312
313 strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
314 inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
315 dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
316
317 // Setup the HINFO SW strings.
318#if ( MDNS_SET_HINFO_STRINGS )
319 mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
320 "mDNSResponder (%s %s)", __DATE__, __TIME__ );
321 inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
322 dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
323#endif
324
325 // Set the thread global overlapped flag
326
327 val = 0;
328 err = setsockopt( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, ( char* ) &val, sizeof( val ) );
329 err = translate_errno( err != SOCKET_ERROR, WSAGetLastError(), kUnknownErr );
330 require_noerr( err, exit );
331
332 // Set up the IPv4 unicast socket
333
334 inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
335 inMDNS->p->unicastSock4.recvMsgPtr = NULL;
336 inMDNS->p->unicastSock4.ifd = NULL;
337 inMDNS->p->unicastSock4.overlapped.pending = FALSE;
338 inMDNS->p->unicastSock4.next = NULL;
339 inMDNS->p->unicastSock4.m = inMDNS;
340
341#if ( MDNS_WINDOWS_ENABLE_IPV4 )
342
343 sa4.sin_family = AF_INET;
344 sa4.sin_addr.s_addr = INADDR_ANY;
345 err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
346 check_noerr( err );
347 sa4len = sizeof( sa4 );
348 err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
349 require_noerr( err, exit );
350 inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
351 inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
352 err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
353
354 if ( err )
355 {
356 inMDNS->p->unicastSock4.recvMsgPtr = NULL;
357 }
358
359 err = UDPBeginRecv( &inMDNS->p->unicastSock4 );
360 require_noerr( err, exit );
361
362#endif
363
364 // Set up the IPv6 unicast socket
365
366 inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
367 inMDNS->p->unicastSock6.recvMsgPtr = NULL;
368 inMDNS->p->unicastSock6.ifd = NULL;
369 inMDNS->p->unicastSock6.overlapped.pending = FALSE;
370 inMDNS->p->unicastSock6.next = NULL;
371 inMDNS->p->unicastSock6.m = inMDNS;
372
373#if ( MDNS_WINDOWS_ENABLE_IPV6 )
374
375 sa6.sin6_family = AF_INET6;
376 sa6.sin6_addr = in6addr_any;
377 sa6.sin6_scope_id = 0;
378
379 // This call will fail if the machine hasn't installed IPv6. In that case,
380 // the error will be WSAEAFNOSUPPORT.
381
382 err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
383 require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
384 err = kNoErr;
385
386 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
387
388 if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
389 {
390 sa6len = sizeof( sa6 );
391 err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
392 require_noerr( err, exit );
393 inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
394 inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
395
396 err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
397
398 if ( err != 0 )
399 {
400 inMDNS->p->unicastSock6.recvMsgPtr = NULL;
401 }
402
403 err = UDPBeginRecv( &inMDNS->p->unicastSock6 );
404 require_noerr( err, exit );
405 }
406
407#endif
408
409 // Notify core of domain secret keys
410
411 SetDomainSecrets( inMDNS );
412
413 // Success!
414
415 mDNSCoreInitComplete( inMDNS, err );
416
417
418exit:
419
420 if ( err )
421 {
422 mDNSPlatformClose( inMDNS );
423 }
424
425 dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
426 return( err );
427}
428
429//===========================================================================================================================
430// mDNSPlatformClose
431//===========================================================================================================================
432
433mDNSexport void mDNSPlatformClose( mDNS * const inMDNS )
434{
435 mStatus err;
436
437 dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
438 check( inMDNS );
439
440 if ( gSMBThread != NULL )
441 {
442 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
443 SetEvent( gSMBThreadStopEvent );
444
445 if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
446 {
447 if ( gSMBThreadQuitEvent )
448 {
449 CloseHandle( gSMBThreadQuitEvent );
450 gSMBThreadQuitEvent = NULL;
451 }
452
453 if ( gSMBThreadStopEvent )
454 {
455 CloseHandle( gSMBThreadStopEvent );
456 gSMBThreadStopEvent = NULL;
457 }
458
459 if ( gSMBThreadDeregisterEvent )
460 {
461 CloseHandle( gSMBThreadDeregisterEvent );
462 gSMBThreadDeregisterEvent = NULL;
463 }
464
465 if ( gSMBThreadRegisterEvent )
466 {
467 CloseHandle( gSMBThreadRegisterEvent );
468 gSMBThreadRegisterEvent = NULL;
469 }
470
471 if ( gDNSSDLibrary )
472 {
473 FreeLibrary( gDNSSDLibrary );
474 gDNSSDLibrary = NULL;
475 }
476 }
477 else
478 {
479 LogMsg( "Unable to stop SMBThread" );
480 }
481
482 inMDNS->p->smbFileSharing = mDNSfalse;
483 inMDNS->p->smbPrintSharing = mDNSfalse;
484 }
485
486 // Tear everything down in reverse order to how it was set up.
487
488 err = TearDownInterfaceList( inMDNS );
489 check_noerr( err );
490 check( !inMDNS->p->inactiveInterfaceList );
491
492#if ( MDNS_WINDOWS_ENABLE_IPV4 )
493
494 UDPCloseSocket( &inMDNS->p->unicastSock4 );
495
496#endif
497
498#if ( MDNS_WINDOWS_ENABLE_IPV6 )
499
500 UDPCloseSocket( &inMDNS->p->unicastSock6 );
501
502#endif
503
504 // Free the DLL needed for IPv6 support.
505
506#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
507 if( gIPHelperLibraryInstance )
508 {
509 gGetAdaptersAddressesFunctionPtr = NULL;
510
511 FreeLibrary( gIPHelperLibraryInstance );
512 gIPHelperLibraryInstance = NULL;
513 }
514#endif
515
516 if ( g_hAAPI32 )
517 {
518 // Release any resources
519
520 if ( g_hProvider && g_lpCryptReleaseContext )
521 {
522 ( g_lpCryptReleaseContext )( g_hProvider, 0 );
523 }
524
525 // Free the AdvApi32.dll
526
527 FreeLibrary( g_hAAPI32 );
528
529 // And reset all the data
530
531 g_lpCryptAcquireContext = NULL;
532 g_lpCryptReleaseContext = NULL;
533 g_lpCryptGenRandom = NULL;
534 g_hProvider = ( ULONG_PTR ) NULL;
535 g_hAAPI32 = NULL;
536 }
537
538 // Clear out the APC queue
539
540 while ( SleepEx( 0, TRUE ) == WAIT_IO_COMPLETION )
541 {
542 DispatchSocketEvents( inMDNS );
543 }
544
545 WSACleanup();
546
547 dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
548}
549
550
551//===========================================================================================================================
552// mDNSPlatformLock
553//===========================================================================================================================
554
555mDNSexport void mDNSPlatformLock( const mDNS * const inMDNS )
556{
557 ( void ) inMDNS;
558}
559
560//===========================================================================================================================
561// mDNSPlatformUnlock
562//===========================================================================================================================
563
564mDNSexport void mDNSPlatformUnlock( const mDNS * const inMDNS )
565{
566 ( void ) inMDNS;
567}
568
569//===========================================================================================================================
570// mDNSPlatformStrCopy
571//===========================================================================================================================
572
573mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
574{
575 check( inSrc );
576 check( inDst );
577
578 strcpy( (char *) inDst, (const char*) inSrc );
579}
580
581//===========================================================================================================================
582// mDNSPlatformStrLCopy
583//===========================================================================================================================
584
585mDNSexport mDNSu32 mDNSPlatformStrLCopy(void *inDst, const void *inSrc, mDNSu32 inSize)
586{
587 const char * src = (const char *) inSrc;
588
589 if( inSize > 0 )
590 {
591 size_t n;
592 char * dst = (char *) inDst;
593
594 for( n = inSize - 1; n > 0; --n )
595 {
596 if( ( *dst++ = *src++ ) == '\0' )
597 {
598 // Null terminator encountered, so exit.
599 goto exit;
600 }
601 }
602 *dst = '\0';
603 }
604
605 while( *src++ != '\0' )
606 {
607 // Stop at null terminator.
608 }
609
610exit:
611 return( (mDNSu32)( src - (const char *) inSrc ) - 1 );
612}
613
614//===========================================================================================================================
615// mDNSPlatformStrLen
616//===========================================================================================================================
617
618mDNSexport mDNSu32 mDNSPlatformStrLen( const void *inSrc )
619{
620 check( inSrc );
621
622 return( (mDNSu32) strlen( (const char *) inSrc ) );
623}
624
625//===========================================================================================================================
626// mDNSPlatformMemCopy
627//===========================================================================================================================
628
629mDNSexport void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
630{
631 check( inSrc );
632 check( inDst );
633
634 memcpy( inDst, inSrc, inSize );
635}
636
637//===========================================================================================================================
638// mDNSPlatformMemSame
639//===========================================================================================================================
640
641mDNSexport mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
642{
643 check( inSrc );
644 check( inDst );
645
646 return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
647}
648
649//===========================================================================================================================
650// mDNSPlatformMemZero
651//===========================================================================================================================
652
653mDNSexport void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
654{
655 check( inDst );
656
657 memset( inDst, 0, inSize );
658}
659
660//===========================================================================================================================
661// mDNSPlatformMemAllocate
662//===========================================================================================================================
663
664mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
665{
666 void * mem;
667
668 check( inSize > 0 );
669
670 mem = malloc( inSize );
671 check( mem );
672
673 return( mem );
674}
675
676//===========================================================================================================================
677// mDNSPlatformMemFree
678//===========================================================================================================================
679
680mDNSexport void mDNSPlatformMemFree( void *inMem )
681{
682 check( inMem );
683
684 free( inMem );
685}
686
687//===========================================================================================================================
688// mDNSPlatformRandomNumber
689//===========================================================================================================================
690
691mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
692{
693 mDNSu32 randomNumber = 0;
694 BOOL bResult;
695 OSStatus err = 0;
696
697 if ( !g_hAAPI32 )
698 {
699 g_hAAPI32 = LoadLibrary( TEXT("AdvAPI32.dll") );
700 err = translate_errno( g_hAAPI32 != NULL, GetLastError(), mStatus_UnknownErr );
701 require_noerr( err, exit );
702 }
703
704 // Function Pointer: CryptAcquireContext
705
706 if ( !g_lpCryptAcquireContext )
707 {
708 g_lpCryptAcquireContext = ( fnCryptAcquireContext )
709#ifdef UNICODE
710 ( GetProcAddress( g_hAAPI32, "CryptAcquireContextW" ) );
711#else
712 ( GetProcAddress( g_hAAPI32, "CryptAcquireContextA" ) );
713#endif
714 err = translate_errno( g_lpCryptAcquireContext != NULL, GetLastError(), mStatus_UnknownErr );
715 require_noerr( err, exit );
716 }
717
718 // Function Pointer: CryptReleaseContext
719
720 if ( !g_lpCryptReleaseContext )
721 {
722 g_lpCryptReleaseContext = ( fnCryptReleaseContext )
723 ( GetProcAddress( g_hAAPI32, "CryptReleaseContext" ) );
724 err = translate_errno( g_lpCryptReleaseContext != NULL, GetLastError(), mStatus_UnknownErr );
725 require_noerr( err, exit );
726 }
727
728 // Function Pointer: CryptGenRandom
729
730 if ( !g_lpCryptGenRandom )
731 {
732 g_lpCryptGenRandom = ( fnCryptGenRandom )
733 ( GetProcAddress( g_hAAPI32, "CryptGenRandom" ) );
734 err = translate_errno( g_lpCryptGenRandom != NULL, GetLastError(), mStatus_UnknownErr );
735 require_noerr( err, exit );
736 }
737
738 // Setup
739
740 if ( !g_hProvider )
741 {
742 bResult = (*g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET );
743
744 if ( !bResult )
745 {
746 bResult = ( *g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET );
747 err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
748 require_noerr( err, exit );
749 }
750 }
751
752 bResult = (*g_lpCryptGenRandom)( g_hProvider, sizeof( randomNumber ), ( BYTE* ) &randomNumber );
753 err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
754 require_noerr( err, exit );
755
756exit:
757
758 if ( err )
759 {
760 randomNumber = rand();
761 }
762
763 return randomNumber;
764}
765
766//===========================================================================================================================
767// mDNSPlatformTimeInit
768//===========================================================================================================================
769
770mDNSexport mStatus mDNSPlatformTimeInit( void )
771{
772 // No special setup is required on Windows -- we just use GetTickCount().
773 return( mStatus_NoError );
774}
775
776//===========================================================================================================================
777// mDNSPlatformRawTime
778//===========================================================================================================================
779
780mDNSexport mDNSs32 mDNSPlatformRawTime( void )
781{
782 return( (mDNSs32) GetTickCount() );
783}
784
785//===========================================================================================================================
786// mDNSPlatformUTC
787//===========================================================================================================================
788
789mDNSexport mDNSs32 mDNSPlatformUTC( void )
790{
791 return ( mDNSs32 ) time( NULL );
792}
793
794//===========================================================================================================================
795// mDNSPlatformInterfaceNameToID
796//===========================================================================================================================
797
798mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
799{
800 mStatus err;
801 mDNSInterfaceData * ifd;
802
803 check( inMDNS );
804 check( inMDNS->p );
805 check( inName );
806
807 // Search for an interface with the specified name,
808
809 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
810 {
811 if( strcmp( ifd->name, inName ) == 0 )
812 {
813 break;
814 }
815 }
816 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
817
818 // Success!
819
820 if( outID )
821 {
822 *outID = (mDNSInterfaceID) ifd;
823 }
824 err = mStatus_NoError;
825
826exit:
827 return( err );
828}
829
830//===========================================================================================================================
831// mDNSPlatformInterfaceIDToInfo
832//===========================================================================================================================
833
834mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
835{
836 mStatus err;
837 mDNSInterfaceData * ifd;
838
839 check( inMDNS );
840 check( inID );
841 check( outInfo );
842
843 // Search for an interface with the specified ID,
844
845 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
846 {
847 if( ifd == (mDNSInterfaceData *) inID )
848 {
849 break;
850 }
851 }
852 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
853
854 // Success!
855
856 outInfo->name = ifd->name;
857 outInfo->ip = ifd->interfaceInfo.ip;
858 err = mStatus_NoError;
859
860exit:
861 return( err );
862}
863
864//===========================================================================================================================
865// mDNSPlatformInterfaceIDfromInterfaceIndex
866//===========================================================================================================================
867
868mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
869{
870 mDNSInterfaceID id;
871
872 id = mDNSNULL;
873 if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
874 {
875 id = mDNSInterface_LocalOnly;
876 }
877 /* uncomment if Windows ever supports P2P
878 else if( inIndex == kDNSServiceInterfaceIndexP2P )
879 {
880 id = mDNSInterface_P2P;
881 }
882 */
883 else if( inIndex != 0 )
884 {
885 mDNSInterfaceData * ifd;
886
887 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
888 {
889 if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
890 {
891 id = ifd->interfaceInfo.InterfaceID;
892 break;
893 }
894 }
895 check( ifd );
896 }
897 return( id );
898}
899
900//===========================================================================================================================
901// mDNSPlatformInterfaceIndexfromInterfaceID
902//===========================================================================================================================
903
904mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSBool suppressNetworkChange )
905{
906 mDNSu32 index;
907 (void) suppressNetworkChange; // Unused
908
909 index = 0;
910 if( inID == mDNSInterface_LocalOnly )
911 {
912 index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
913 }
914 /* uncomment if Windows ever supports P2P
915 else if( inID == mDNSInterface_P2P )
916 {
917 index = (mDNSu32) kDNSServiceInterfaceIndexP2P;
918 }
919 */
920 else if( inID )
921 {
922 mDNSInterfaceData * ifd;
923
924 // Search active interfaces.
925 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
926 {
927 if( (mDNSInterfaceID) ifd == inID )
928 {
929 index = ifd->scopeID;
930 break;
931 }
932 }
933
934 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
935
936 if( !ifd )
937 {
938 for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
939 {
940 if( (mDNSInterfaceID) ifd == inID )
941 {
942 index = ifd->scopeID;
943 break;
944 }
945 }
946 }
947 check( ifd );
948 }
949 return( index );
950}
951
952
953//===========================================================================================================================
954// mDNSPlatformTCPSocket
955//===========================================================================================================================
956
957TCPSocket *
958mDNSPlatformTCPSocket
959 (
960 mDNS * const m,
961 TCPSocketFlags flags,
962 mDNSIPPort * port
963 )
964{
965 TCPSocket * sock = NULL;
966 u_long on = 1; // "on" for setsockopt
967 struct sockaddr_in saddr;
968 int len;
969 mStatus err = mStatus_NoError;
970
971 DEBUG_UNUSED( m );
972
973 require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
974
975 // Setup connection data object
976
977 sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
978 require_action( sock, exit, err = mStatus_NoMemoryErr );
979 mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
980 sock->fd = INVALID_SOCKET;
981 sock->flags = flags;
982 sock->m = m;
983
984 mDNSPlatformMemZero(&saddr, sizeof(saddr));
985 saddr.sin_family = AF_INET;
986 saddr.sin_addr.s_addr = htonl( INADDR_ANY );
987 saddr.sin_port = port->NotAnInteger;
988
989 // Create the socket
990
991 sock->fd = socket(AF_INET, SOCK_STREAM, 0);
992 err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
993 require_noerr( err, exit );
994
995 // bind
996
997 err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
998 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
999 require_noerr( err, exit );
1000
1001 // Set it to be non-blocking
1002
1003 err = ioctlsocket( sock->fd, FIONBIO, &on );
1004 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
1005 require_noerr( err, exit );
1006
1007 // Get port number
1008
1009 mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
1010 len = sizeof( saddr );
1011
1012 err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
1013 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
1014 require_noerr( err, exit );
1015
1016 port->NotAnInteger = saddr.sin_port;
1017
1018exit:
1019
1020 if ( err && sock )
1021 {
1022 TCPFreeSocket( sock );
1023 sock = mDNSNULL;
1024 }
1025
1026 return sock;
1027}
1028
1029//===========================================================================================================================
1030// mDNSPlatformTCPConnect
1031//===========================================================================================================================
1032
1033mStatus
1034mDNSPlatformTCPConnect
1035 (
1036 TCPSocket * sock,
1037 const mDNSAddr * inDstIP,
1038 mDNSOpaque16 inDstPort,
1039 domainname * hostname,
1040 mDNSInterfaceID inInterfaceID,
1041 TCPConnectionCallback inCallback,
1042 void * inContext
1043 )
1044{
1045 struct sockaddr_in saddr;
1046 mStatus err = mStatus_NoError;
1047
1048 DEBUG_UNUSED( inInterfaceID );
1049 ( void ) hostname;
1050
1051 if ( inDstIP->type != mDNSAddrType_IPv4 )
1052 {
1053 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1054 return mStatus_UnknownErr;
1055 }
1056
1057 // Setup connection data object
1058
1059 sock->readEventHandler = TCPCanRead;
1060 sock->userCallback = inCallback;
1061 sock->userContext = inContext;
1062
1063 mDNSPlatformMemZero(&saddr, sizeof(saddr));
1064 saddr.sin_family = AF_INET;
1065 saddr.sin_port = inDstPort.NotAnInteger;
1066 memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
1067
1068 // Try and do connect
1069
1070 err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
1071 require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
1072 sock->connected = !err ? TRUE : FALSE;
1073
1074 if ( sock->connected )
1075 {
1076 err = TCPAddSocket( sock->m, sock );
1077 require_noerr( err, exit );
1078 }
1079 else
1080 {
1081 require_action( sock->m->p->registerWaitableEventFunc != NULL, exit, err = mStatus_ConnFailed );
1082
1083 sock->connectEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1084 err = translate_errno( sock->connectEvent, GetLastError(), mStatus_UnknownErr );
1085 require_noerr( err, exit );
1086
1087 err = WSAEventSelect( sock->fd, sock->connectEvent, FD_CONNECT );
1088 require_noerr( err, exit );
1089
1090 err = sock->m->p->registerWaitableEventFunc( sock->m, sock->connectEvent, sock, TCPDidConnect );
1091 require_noerr( err, exit );
1092 }
1093
1094exit:
1095
1096 if ( !err )
1097 {
1098 err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
1099 }
1100
1101 return err;
1102}
1103
1104//===========================================================================================================================
1105// mDNSPlatformTCPAccept
1106//===========================================================================================================================
1107
1108mDNSexport
1109mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
1110 {
1111 TCPSocket * sock = NULL;
1112 mStatus err = mStatus_NoError;
1113
1114 require_action( !flags, exit, err = mStatus_UnsupportedErr );
1115
1116 sock = malloc( sizeof( TCPSocket ) );
1117 require_action( sock, exit, err = mStatus_NoMemoryErr );
1118
1119 mDNSPlatformMemZero( sock, sizeof( *sock ) );
1120
1121 sock->fd = fd;
1122 sock->flags = flags;
1123
1124exit:
1125
1126 if ( err && sock )
1127 {
1128 free( sock );
1129 sock = NULL;
1130 }
1131
1132 return sock;
1133 }
1134
1135
1136//===========================================================================================================================
1137// mDNSPlatformTCPCloseConnection
1138//===========================================================================================================================
1139
1140mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
1141{
1142 check( sock );
1143
1144 if ( sock->connectEvent && sock->m->p->unregisterWaitableEventFunc )
1145 {
1146 sock->m->p->unregisterWaitableEventFunc( sock->m, sock->connectEvent );
1147 }
1148
1149 if ( sock->fd != INVALID_SOCKET )
1150 {
1151 TCPCloseSocket( sock );
1152
1153 QueueUserAPC( ( PAPCFUNC ) TCPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
1154 }
1155}
1156
1157
1158//===========================================================================================================================
1159// mDNSPlatformReadTCP
1160//===========================================================================================================================
1161
1162mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
1163{
1164 unsigned long bytesLeft;
1165 int wsaError;
1166 long ret;
1167
1168 *closed = sock->closed;
1169 wsaError = sock->lastError;
1170 ret = -1;
1171
1172 if ( *closed )
1173 {
1174 ret = 0;
1175 }
1176 else if ( sock->lastError == 0 )
1177 {
1178 // First check to see if we have any data left in our buffer
1179
1180 bytesLeft = ( DWORD ) ( sock->eptr - sock->bptr );
1181
1182 if ( bytesLeft )
1183 {
1184 unsigned long bytesToCopy = ( bytesLeft < inBufferSize ) ? bytesLeft : inBufferSize;
1185
1186 memcpy( inBuffer, sock->bptr, bytesToCopy );
1187 sock->bptr += bytesToCopy;
1188
1189 if ( !sock->overlapped.pending && ( sock->bptr == sock->eptr ) )
1190 {
1191 sock->bptr = sock->bbuf;
1192 sock->eptr = sock->bbuf;
1193 }
1194
1195 ret = bytesToCopy;
1196 }
1197 else
1198 {
1199 wsaError = WSAEWOULDBLOCK;
1200 }
1201 }
1202
1203 // Always set the last winsock error, so that we don't inadvertently use a previous one
1204
1205 WSASetLastError( wsaError );
1206
1207 return ret;
1208}
1209
1210
1211//===========================================================================================================================
1212// mDNSPlatformWriteTCP
1213//===========================================================================================================================
1214
1215mDNSexport long mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
1216{
1217 int nsent;
1218 OSStatus err;
1219
1220 nsent = send( sock->fd, inMsg, inMsgSize, 0 );
1221
1222 err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
1223 require_noerr( err, exit );
1224
1225 if ( nsent < 0)
1226 {
1227 nsent = 0;
1228 }
1229
1230exit:
1231
1232 return nsent;
1233}
1234
1235//===========================================================================================================================
1236// mDNSPlatformTCPGetFD
1237//===========================================================================================================================
1238
1239mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
1240{
1241 return ( int ) sock->fd;
1242}
1243
1244
1245//===========================================================================================================================
1246// TCPAddConnection
1247//===========================================================================================================================
1248
1249mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock )
1250{
1251 mStatus err;
1252
1253 ( void ) inMDNS;
1254
1255 sock->bptr = sock->bbuf;
1256 sock->eptr = sock->bbuf;
1257 sock->ebuf = sock->bbuf + sizeof( sock->bbuf );
1258
1259 dlog( kDebugLevelChatty, DEBUG_NAME "adding TCPSocket 0x%x:%d\n", sock, sock->fd );
1260 err = TCPBeginRecv( sock );
1261 require_noerr( err, exit );
1262
1263exit:
1264
1265 return err;
1266}
1267
1268
1269//===========================================================================================================================
1270// TCPDidConnect
1271//===========================================================================================================================
1272
1273mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context )
1274{
1275 TCPSocket * sock = ( TCPSocket* ) context;
1276 TCPConnectionCallback callback = NULL;
1277 WSANETWORKEVENTS sockEvent;
1278 int err = kNoErr;
1279
1280 if ( inMDNS->p->unregisterWaitableEventFunc )
1281 {
1282 inMDNS->p->unregisterWaitableEventFunc( inMDNS, event );
1283 }
1284
1285 if ( sock )
1286 {
1287 callback = ( TCPConnectionCallback ) sock->userCallback;
1288 err = WSAEnumNetworkEvents( sock->fd, sock->connectEvent, &sockEvent );
1289 require_noerr( err, exit );
1290 require_action( sockEvent.lNetworkEvents & FD_CONNECT, exit, err = mStatus_UnknownErr );
1291 require_action( sockEvent.iErrorCode[ FD_CONNECT_BIT ] == 0, exit, err = sockEvent.iErrorCode[ FD_CONNECT_BIT ] );
1292
1293 sock->connected = mDNStrue;
1294
1295 if ( sock->fd != INVALID_SOCKET )
1296 {
1297 err = TCPAddSocket( sock->m, sock );
1298 require_noerr( err, exit );
1299 }
1300
1301 if ( callback )
1302 {
1303 callback( sock, sock->userContext, TRUE, 0 );
1304 }
1305 }
1306
1307exit:
1308
1309 if ( err && callback )
1310 {
1311 callback( sock, sock->userContext, TRUE, err );
1312 }
1313}
1314
1315
1316
1317//===========================================================================================================================
1318// TCPCanRead
1319//===========================================================================================================================
1320
1321mDNSlocal void TCPCanRead( TCPSocket * sock )
1322{
1323 TCPConnectionCallback callback = ( TCPConnectionCallback ) sock->userCallback;
1324
1325 if ( callback )
1326 {
1327 callback( sock, sock->userContext, mDNSfalse, sock->lastError );
1328 }
1329}
1330
1331
1332//===========================================================================================================================
1333// TCPBeginRecv
1334//===========================================================================================================================
1335
1336mDNSlocal mStatus TCPBeginRecv( TCPSocket * sock )
1337{
1338 DWORD bytesReceived = 0;
1339 DWORD flags = 0;
1340 mStatus err;
1341
1342 dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
1343
1344 check( !sock->overlapped.pending );
1345
1346 ZeroMemory( &sock->overlapped.data, sizeof( sock->overlapped.data ) );
1347 sock->overlapped.data.hEvent = sock;
1348
1349 sock->overlapped.wbuf.buf = ( char* ) sock->eptr;
1350 sock->overlapped.wbuf.len = ( ULONG) ( sock->ebuf - sock->eptr );
1351
1352 err = WSARecv( sock->fd, &sock->overlapped.wbuf, 1, &bytesReceived, &flags, &sock->overlapped.data, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) TCPEndRecv );
1353 err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), WSAGetLastError(), kUnknownErr );
1354 require_noerr( err, exit );
1355
1356 sock->overlapped.pending = TRUE;
1357
1358exit:
1359
1360 return err;
1361}
1362
1363
1364//===========================================================================================================================
1365// TCPEndRecv
1366//===========================================================================================================================
1367
1368mDNSlocal void CALLBACK TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
1369{
1370 TCPSocket * sock;
1371
1372 ( void ) flags;
1373
1374 dlog( kDebugLevelChatty, DEBUG_NAME "%s: error = %d, bytesTransferred = %d\n", __ROUTINE__, error, bytesTransferred );
1375 sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
1376 require_action( sock, exit, error = ( DWORD ) mStatus_BadStateErr );
1377 dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
1378 sock->overlapped.error = error;
1379 sock->overlapped.bytesTransferred = bytesTransferred;
1380 check( sock->overlapped.pending );
1381 sock->overlapped.pending = FALSE;
1382
1383 // Queue this socket
1384
1385 AddToTail( &gTCPDispatchableSockets, sock );
1386
1387exit:
1388
1389 return;
1390}
1391
1392
1393
1394//===========================================================================================================================
1395// mDNSPlatformUDPSocket
1396//===========================================================================================================================
1397
1398mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
1399{
1400 UDPSocket* sock = NULL;
1401 mDNSIPPort port = requestedport;
1402 mStatus err = mStatus_NoError;
1403 unsigned i;
1404
1405 // Setup connection data object
1406
1407 sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
1408 require_action( sock, exit, err = mStatus_NoMemoryErr );
1409 memset( sock, 0, sizeof( UDPSocket ) );
1410
1411 // Create the socket
1412
1413 sock->fd = INVALID_SOCKET;
1414 sock->recvMsgPtr = m->p->unicastSock4.recvMsgPtr;
1415 sock->addr = m->p->unicastSock4.addr;
1416 sock->ifd = NULL;
1417 sock->overlapped.pending = FALSE;
1418 sock->m = m;
1419
1420 // Try at most 10000 times to get a unique random port
1421
1422 for (i=0; i<10000; i++)
1423 {
1424 struct sockaddr_in saddr;
1425
1426 saddr.sin_family = AF_INET;
1427 saddr.sin_addr.s_addr = 0;
1428
1429 // The kernel doesn't do cryptographically strong random port
1430 // allocation, so we do it ourselves here
1431
1432 if (mDNSIPPortIsZero(requestedport))
1433 {
1434 port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
1435 }
1436
1437 saddr.sin_port = port.NotAnInteger;
1438
1439 err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
1440 if (!err) break;
1441 }
1442
1443 require_noerr( err, exit );
1444
1445 // Set the port
1446
1447 sock->port = port;
1448
1449 // Arm the completion routine
1450
1451 err = UDPBeginRecv( sock );
1452 require_noerr( err, exit );
1453
1454 // Bookkeeping
1455
1456 sock->next = gUDPSockets;
1457 gUDPSockets = sock;
1458 gUDPNumSockets++;
1459
1460exit:
1461
1462 if ( err && sock )
1463 {
1464 UDPFreeSocket( sock );
1465 sock = NULL;
1466 }
1467
1468 return sock;
1469}
1470
1471//===========================================================================================================================
1472// mDNSPlatformUDPClose
1473//===========================================================================================================================
1474
1475mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
1476{
1477 UDPSocket * current = gUDPSockets;
1478 UDPSocket * last = NULL;
1479
1480 while ( current )
1481 {
1482 if ( current == sock )
1483 {
1484 if ( last == NULL )
1485 {
1486 gUDPSockets = sock->next;
1487 }
1488 else
1489 {
1490 last->next = sock->next;
1491 }
1492
1493 // Alertable I/O is great, except not so much when it comes to closing
1494 // the socket. Anything that has been previously queued for this socket
1495 // will stay in the queue after you close the socket. This is problematic
1496 // for obvious reasons. So we'll attempt to workaround this by closing
1497 // the socket which will prevent any further queued packets and then not calling
1498 // UDPFreeSocket directly, but by queueing it using QueueUserAPC. The queues
1499 // are FIFO, so that will execute *after* any other previous items in the queue
1500 //
1501 // UDPEndRecv will check if the socket is valid, and if not, it will ignore
1502 // the packet
1503
1504 UDPCloseSocket( sock );
1505
1506 QueueUserAPC( ( PAPCFUNC ) UDPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
1507
1508 gUDPNumSockets--;
1509
1510 break;
1511 }
1512
1513 last = current;
1514 current = current->next;
1515 }
1516}
1517
1518
1519//===========================================================================================================================
1520// mDNSPlatformSendUDP
1521//===========================================================================================================================
1522
1523mDNSexport mStatus
1524 mDNSPlatformSendUDP(
1525 const mDNS * const inMDNS,
1526 const void * const inMsg,
1527 const mDNSu8 * const inMsgEnd,
1528 mDNSInterfaceID inInterfaceID,
1529 UDPSocket * inSrcSocket,
1530 const mDNSAddr * inDstIP,
1531 mDNSIPPort inDstPort )
1532{
1533 SOCKET sendingsocket = INVALID_SOCKET;
1534 mStatus err = mStatus_NoError;
1535 mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID;
1536 struct sockaddr_storage addr;
1537 int n;
1538
1539 DEBUG_USE_ONLY( inMDNS );
1540
1541 n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
1542 check( inMDNS );
1543 check( inMsg );
1544 check( inMsgEnd );
1545 check( inDstIP );
1546
1547 dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
1548
1549 if( inDstIP->type == mDNSAddrType_IPv4 )
1550 {
1551 struct sockaddr_in * sa4;
1552
1553 sa4 = (struct sockaddr_in *) &addr;
1554 sa4->sin_family = AF_INET;
1555 sa4->sin_port = inDstPort.NotAnInteger;
1556 sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
1557 sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
1558
1559 if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
1560 }
1561 else if( inDstIP->type == mDNSAddrType_IPv6 )
1562 {
1563 struct sockaddr_in6 * sa6;
1564
1565 sa6 = (struct sockaddr_in6 *) &addr;
1566 sa6->sin6_family = AF_INET6;
1567 sa6->sin6_port = inDstPort.NotAnInteger;
1568 sa6->sin6_flowinfo = 0;
1569 sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
1570 sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
1571 sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
1572 }
1573 else
1574 {
1575 dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
1576 err = mStatus_BadParamErr;
1577 goto exit;
1578 }
1579
1580 if (IsValidSocket(sendingsocket))
1581 {
1582 n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
1583 err = translate_errno( n > 0, errno_compat(), kWriteErr );
1584
1585 if ( err )
1586 {
1587 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1588
1589 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
1590 {
1591 err = mStatus_TransientErr;
1592 }
1593 else
1594 {
1595 require_noerr( err, exit );
1596 }
1597 }
1598 }
1599
1600exit:
1601 return( err );
1602}
1603
1604
1605mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
1606 {
1607 DEBUG_UNUSED( m );
1608 DEBUG_UNUSED( InterfaceID );
1609 }
1610
1611//===========================================================================================================================
1612// mDNSPlatformSendRawPacket
1613//===========================================================================================================================
1614
1615mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
1616 {
1617 DEBUG_UNUSED( m );
1618 DEBUG_UNUSED( allowSleep );
1619 DEBUG_UNUSED( reason );
1620 }
1621
1622mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
1623 {
1624 DEBUG_UNUSED( msg );
1625 DEBUG_UNUSED( end );
1626 DEBUG_UNUSED( InterfaceID );
1627 }
1628
1629mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
1630 {
1631 DEBUG_UNUSED( msg );
1632 DEBUG_UNUSED( end );
1633 DEBUG_UNUSED( InterfaceID );
1634 }
1635
1636mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
1637 {
1638 DEBUG_UNUSED( m );
1639 DEBUG_UNUSED( tpa );
1640 DEBUG_UNUSED( tha );
1641 DEBUG_UNUSED( InterfaceID );
1642 }
1643
1644mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
1645 {
1646 dlog( kDebugLevelInfo, "%s\n", msg );
1647 }
1648
1649mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
1650 {
1651 extern mDNS mDNSStorage;
1652 int type;
1653
1654 DEBUG_UNUSED( ident );
1655
1656 type = EVENTLOG_ERROR_TYPE;
1657
1658 switch (loglevel)
1659 {
1660 case MDNS_LOG_MSG: type = EVENTLOG_ERROR_TYPE; break;
1661 case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE; break;
1662 case MDNS_LOG_SPS: type = EVENTLOG_INFORMATION_TYPE; break;
1663 case MDNS_LOG_INFO: type = EVENTLOG_INFORMATION_TYPE; break;
1664 case MDNS_LOG_DEBUG: type = EVENTLOG_INFORMATION_TYPE; break;
1665 default:
1666 fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
1667 fflush(stderr);
1668 }
1669
1670 mDNSStorage.p->reportStatusFunc( type, msg );
1671 dlog( kDebugLevelInfo, "%s\n", msg );
1672 }
1673
1674mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
1675 {
1676 DEBUG_UNUSED( src );
1677 DEBUG_UNUSED( dst );
1678 }
1679
1680//===========================================================================================================================
1681// mDNSPlatformTLSSetupCerts
1682//===========================================================================================================================
1683
1684mDNSexport mStatus
1685mDNSPlatformTLSSetupCerts(void)
1686{
1687 return mStatus_UnsupportedErr;
1688}
1689
1690//===========================================================================================================================
1691// mDNSPlatformTLSTearDownCerts
1692//===========================================================================================================================
1693
1694mDNSexport void
1695mDNSPlatformTLSTearDownCerts(void)
1696{
1697}
1698
1699//===========================================================================================================================
1700// mDNSPlatformSetDNSConfig
1701//===========================================================================================================================
1702
1703mDNSlocal void SetDNSServers( mDNS *const m );
1704mDNSlocal void SetSearchDomainList( void );
1705
1706mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains)
1707{
1708 if (setservers) SetDNSServers(m);
1709 if (setsearch) SetSearchDomainList();
1710
1711 if ( fqdn )
1712 {
1713 GetDDNSFQDN( fqdn );
1714 }
1715
1716 if ( browseDomains )
1717 {
1718 GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
1719 }
1720
1721 if ( regDomains )
1722 {
1723 GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
1724 }
1725}
1726
1727
1728//===========================================================================================================================
1729// mDNSPlatformDynDNSHostNameStatusChanged
1730//===========================================================================================================================
1731
1732mDNSexport void
1733mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
1734{
1735 char uname[MAX_ESCAPED_DOMAIN_NAME];
1736 BYTE bStatus;
1737 LPCTSTR name;
1738 HKEY key = NULL;
1739 mStatus err;
1740 char * p;
1741
1742 ConvertDomainNameToCString(dname, uname);
1743
1744 p = uname;
1745
1746 while (*p)
1747 {
1748 *p = (char) tolower(*p);
1749 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
1750 p++;
1751 }
1752
1753 check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
1754 name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
1755 err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
1756 require_noerr( err, exit );
1757
1758 bStatus = ( status ) ? 0 : 1;
1759 err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
1760 require_noerr( err, exit );
1761
1762exit:
1763
1764 if ( key )
1765 {
1766 RegCloseKey( key );
1767 }
1768
1769 return;
1770}
1771
1772
1773mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
1774 {
1775 (void)m; // unused
1776 (void)rr;
1777 (void)result;
1778 }
1779
1780
1781
1782//===========================================================================================================================
1783// SetDomainSecrets
1784//===========================================================================================================================
1785
1786// This routine needs to be called whenever the system secrets database changes.
1787// We call it from DynDNSConfigDidChange and mDNSPlatformInit
1788
1789void
1790SetDomainSecrets( mDNS * const m )
1791{
1792 DomainAuthInfo *ptr;
1793 domainname fqdn;
1794 DNameListElem * regDomains = NULL;
1795
1796 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
1797 // In the case where the user simultaneously removes their DDNS host name and the key
1798 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
1799 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
1800 // address records behind that we no longer have permission to delete.
1801
1802 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
1803 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
1804
1805 GetDDNSFQDN( &fqdn );
1806
1807 if ( fqdn.c[ 0 ] )
1808 {
1809 SetDomainSecret( m, &fqdn );
1810 }
1811
1812 GetDDNSDomains( &regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
1813
1814 while ( regDomains )
1815 {
1816 DNameListElem * current = regDomains;
1817 SetDomainSecret( m, &current->name );
1818 regDomains = regDomains->next;
1819 free( current );
1820 }
1821}
1822
1823
1824//===========================================================================================================================
1825// SetSearchDomainList
1826//===========================================================================================================================
1827
1828mDNSlocal void SetDomainFromDHCP( void );
1829mDNSlocal void SetReverseMapSearchDomainList( void );
1830
1831mDNSlocal void
1832SetSearchDomainList( void )
1833{
1834 char * searchList = NULL;
1835 DWORD searchListLen;
1836 //DNameListElem * head = NULL;
1837 //DNameListElem * current = NULL;
1838 char * tok;
1839 HKEY key;
1840 mStatus err;
1841
1842 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
1843 require_noerr( err, exit );
1844
1845 err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
1846 require_noerr( err, exit );
1847
1848 // Windows separates the search domains with ','
1849
1850 tok = strtok( searchList, "," );
1851 while ( tok )
1852 {
1853 if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
1854 mDNS_AddSearchDomain_CString(tok, mDNSNULL);
1855 tok = strtok( NULL, "," );
1856 }
1857
1858exit:
1859
1860 if ( searchList )
1861 {
1862 free( searchList );
1863 }
1864
1865 if ( key )
1866 {
1867 RegCloseKey( key );
1868 }
1869
1870 SetDomainFromDHCP();
1871 SetReverseMapSearchDomainList();
1872}
1873
1874
1875//===========================================================================================================================
1876// SetReverseMapSearchDomainList
1877//===========================================================================================================================
1878
1879mDNSlocal void
1880SetReverseMapSearchDomainList( void )
1881{
1882 struct ifaddrs * ifa;
1883
1884 ifa = myGetIfAddrs( 1 );
1885 while (ifa)
1886 {
1887 mDNSAddr addr;
1888
1889 if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
1890 {
1891 mDNSAddr netmask;
1892 char buffer[256];
1893
1894 if (!SetupAddr(&netmask, ifa->ifa_netmask))
1895 {
1896 sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
1897 addr.ip.v4.b[2] & netmask.ip.v4.b[2],
1898 addr.ip.v4.b[1] & netmask.ip.v4.b[1],
1899 addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
1900 mDNS_AddSearchDomain_CString(buffer, mDNSNULL);
1901 }
1902 }
1903
1904 ifa = ifa->ifa_next;
1905 }
1906
1907 return;
1908}
1909
1910
1911//===========================================================================================================================
1912// SetDNSServers
1913//===========================================================================================================================
1914
1915mDNSlocal void
1916SetDNSServers( mDNS *const m )
1917{
1918 PIP_PER_ADAPTER_INFO pAdapterInfo = NULL;
1919 FIXED_INFO * fixedInfo = NULL;
1920 ULONG bufLen = 0;
1921 IP_ADDR_STRING * dnsServerList;
1922 IP_ADDR_STRING * ipAddr;
1923 DWORD index;
1924 int i = 0;
1925 mStatus err = kUnknownErr;
1926
1927 // Get the primary interface.
1928
1929 index = GetPrimaryInterface();
1930
1931 // This should have the interface index of the primary index. Fall back in cases where
1932 // it can't be determined.
1933
1934 if ( index )
1935 {
1936 bufLen = 0;
1937
1938 for ( i = 0; i < 100; i++ )
1939 {
1940 err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
1941
1942 if ( err != ERROR_BUFFER_OVERFLOW )
1943 {
1944 break;
1945 }
1946
1947 pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
1948 require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
1949 }
1950
1951 require_noerr( err, exit );
1952
1953 dnsServerList = &pAdapterInfo->DnsServerList;
1954 }
1955 else
1956 {
1957 bufLen = sizeof( FIXED_INFO );
1958
1959 for ( i = 0; i < 100; i++ )
1960 {
1961 if ( fixedInfo )
1962 {
1963 GlobalFree( fixedInfo );
1964 fixedInfo = NULL;
1965 }
1966
1967 fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
1968 require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
1969
1970 err = GetNetworkParams( fixedInfo, &bufLen );
1971
1972 if ( err != ERROR_BUFFER_OVERFLOW )
1973 {
1974 break;
1975 }
1976 }
1977
1978 require_noerr( err, exit );
1979
1980 dnsServerList = &fixedInfo->DnsServerList;
1981 }
1982
1983 for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
1984 {
1985 mDNSAddr addr;
1986 err = StringToAddress( &addr, ipAddr->IpAddress.String );
1987 if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort, mDNSfalse, 0);
1988 }
1989
1990exit:
1991
1992 if ( pAdapterInfo )
1993 {
1994 free( pAdapterInfo );
1995 }
1996
1997 if ( fixedInfo )
1998 {
1999 GlobalFree( fixedInfo );
2000 }
2001}
2002
2003
2004//===========================================================================================================================
2005// SetDomainFromDHCP
2006//===========================================================================================================================
2007
2008mDNSlocal void
2009SetDomainFromDHCP( void )
2010{
2011 int i = 0;
2012 IP_ADAPTER_INFO * pAdapterInfo;
2013 IP_ADAPTER_INFO * pAdapter;
2014 DWORD bufLen;
2015 DWORD index;
2016 HKEY key = NULL;
2017 LPSTR domain = NULL;
2018 DWORD dwSize;
2019 mStatus err = mStatus_NoError;
2020
2021 pAdapterInfo = NULL;
2022
2023 for ( i = 0; i < 100; i++ )
2024 {
2025 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2026
2027 if ( err != ERROR_BUFFER_OVERFLOW )
2028 {
2029 break;
2030 }
2031
2032 pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
2033 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2034 }
2035
2036 require_noerr( err, exit );
2037
2038 index = GetPrimaryInterface();
2039
2040 for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
2041 {
2042 if ( pAdapter->IpAddressList.IpAddress.String &&
2043 pAdapter->IpAddressList.IpAddress.String[0] &&
2044 pAdapter->GatewayList.IpAddress.String &&
2045 pAdapter->GatewayList.IpAddress.String[0] &&
2046 ( !index || ( pAdapter->Index == index ) ) )
2047 {
2048 // Found one that will work
2049
2050 char keyName[1024];
2051
2052 _snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
2053
2054 err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
2055 require_noerr( err, exit );
2056
2057 err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
2058 check_noerr( err );
2059
2060 if ( !domain || !domain[0] )
2061 {
2062 if ( domain )
2063 {
2064 free( domain );
2065 domain = NULL;
2066 }
2067
2068 err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
2069 check_noerr( err );
2070 }
2071
2072 if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain, mDNSNULL);
2073
2074 break;
2075 }
2076 }
2077
2078exit:
2079
2080 if ( pAdapterInfo )
2081 {
2082 free( pAdapterInfo );
2083 }
2084
2085 if ( domain )
2086 {
2087 free( domain );
2088 }
2089
2090 if ( key )
2091 {
2092 RegCloseKey( key );
2093 }
2094}
2095
2096
2097//===========================================================================================================================
2098// mDNSPlatformGetPrimaryInterface
2099//===========================================================================================================================
2100
2101mDNSexport mStatus
2102mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
2103{
2104 IP_ADAPTER_INFO * pAdapterInfo;
2105 IP_ADAPTER_INFO * pAdapter;
2106 DWORD bufLen;
2107 int i;
2108 BOOL found;
2109 DWORD index;
2110 mStatus err = mStatus_NoError;
2111
2112 DEBUG_UNUSED( m );
2113
2114 *v6 = zeroAddr;
2115
2116 pAdapterInfo = NULL;
2117 bufLen = 0;
2118 found = FALSE;
2119
2120 for ( i = 0; i < 100; i++ )
2121 {
2122 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2123
2124 if ( err != ERROR_BUFFER_OVERFLOW )
2125 {
2126 break;
2127 }
2128
2129 pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
2130 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2131 }
2132
2133 require_noerr( err, exit );
2134
2135 index = GetPrimaryInterface();
2136
2137 for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
2138 {
2139 if ( pAdapter->IpAddressList.IpAddress.String &&
2140 pAdapter->IpAddressList.IpAddress.String[0] &&
2141 pAdapter->GatewayList.IpAddress.String &&
2142 pAdapter->GatewayList.IpAddress.String[0] &&
2143 ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
2144 ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
2145 ( !index || ( pAdapter->Index == index ) ) )
2146 {
2147 // Found one that will work
2148
2149 if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
2150 {
2151 memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
2152 }
2153
2154 found = TRUE;
2155 break;
2156 }
2157 }
2158
2159exit:
2160
2161 if ( pAdapterInfo )
2162 {
2163 free( pAdapterInfo );
2164 }
2165
2166 return err;
2167}
2168
2169mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
2170 {
2171 (void) m;
2172 (void) InterfaceID;
2173 (void) EthAddr;
2174 (void) IPAddr;
2175 (void) iteration;
2176 }
2177
2178mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
2179 {
2180 (void) rr;
2181 (void) intf;
2182
2183 return 1;
2184 }
2185
2186
2187#if 0
2188#pragma mark -
2189#endif
2190
2191//===========================================================================================================================
2192// debugf_
2193//===========================================================================================================================
2194#if( MDNS_DEBUGMSGS )
2195mDNSexport void debugf_( const char *inFormat, ... )
2196{
2197 char buffer[ 512 ];
2198 va_list args;
2199 mDNSu32 length;
2200
2201 va_start( args, inFormat );
2202 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2203 va_end( args );
2204
2205 dlog( kDebugLevelInfo, "%s\n", buffer );
2206}
2207#endif
2208
2209//===========================================================================================================================
2210// verbosedebugf_
2211//===========================================================================================================================
2212
2213#if( MDNS_DEBUGMSGS > 1 )
2214mDNSexport void verbosedebugf_( const char *inFormat, ... )
2215{
2216 char buffer[ 512 ];
2217 va_list args;
2218 mDNSu32 length;
2219
2220 va_start( args, inFormat );
2221 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2222 va_end( args );
2223
2224 dlog( kDebugLevelVerbose, "%s\n", buffer );
2225}
2226#endif
2227
2228
2229#if 0
2230#pragma mark -
2231#pragma mark == Platform Internals ==
2232#endif
2233
2234
2235//===========================================================================================================================
2236// SetupNiceName
2237//===========================================================================================================================
2238
2239mStatus SetupNiceName( mDNS * const inMDNS )
2240{
2241 HKEY descKey = NULL;
2242 char utf8[ 256 ];
2243 LPCTSTR s;
2244 LPWSTR joinName;
2245 NETSETUP_JOIN_STATUS joinStatus;
2246 mStatus err = 0;
2247 DWORD namelen;
2248 BOOL ok;
2249
2250 check( inMDNS );
2251
2252 // Set up the nice name.
2253 utf8[0] = '\0';
2254
2255 // First try and open the registry key that contains the computer description value
2256 s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2257 err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
2258 check_translated_errno( err == 0, errno_compat(), kNameErr );
2259
2260 if ( !err )
2261 {
2262 TCHAR desc[256];
2263 DWORD descSize = sizeof( desc );
2264
2265 // look for the computer description
2266 err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
2267
2268 if ( !err )
2269 {
2270 err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
2271 }
2272
2273 if ( err )
2274 {
2275 utf8[ 0 ] = '\0';
2276 }
2277 }
2278
2279 // if we can't find it in the registry, then use the hostname of the machine
2280 if ( err || ( utf8[ 0 ] == '\0' ) )
2281 {
2282 TCHAR hostname[256];
2283
2284 namelen = sizeof( hostname ) / sizeof( TCHAR );
2285
2286 ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
2287 err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
2288 check_noerr( err );
2289
2290 if( !err )
2291 {
2292 err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
2293 }
2294
2295 if ( err )
2296 {
2297 utf8[ 0 ] = '\0';
2298 }
2299 }
2300
2301 // if we can't get the hostname
2302 if ( err || ( utf8[ 0 ] == '\0' ) )
2303 {
2304 // Invalidate name so fall back to a default name.
2305
2306 strcpy( utf8, kMDNSDefaultName );
2307 }
2308
2309 utf8[ sizeof( utf8 ) - 1 ] = '\0';
2310 inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
2311 memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
2312
2313 dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
2314
2315 if ( descKey )
2316 {
2317 RegCloseKey( descKey );
2318 }
2319
2320 ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
2321 ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
2322
2323 namelen = sizeof( inMDNS->p->nbname );
2324 ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
2325 check( ok );
2326 if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
2327
2328 err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
2329 check ( err == NERR_Success );
2330 if ( err == NERR_Success )
2331 {
2332 if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
2333 {
2334 err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
2335 check( !err );
2336 if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
2337 }
2338
2339 NetApiBufferFree( joinName );
2340 joinName = NULL;
2341 }
2342
2343 err = 0;
2344
2345 return( err );
2346}
2347
2348//===========================================================================================================================
2349// SetupHostName
2350//===========================================================================================================================
2351
2352mDNSlocal mStatus SetupHostName( mDNS * const inMDNS )
2353{
2354 mStatus err = 0;
2355 char tempString[ 256 ];
2356 DWORD tempStringLen;
2357 domainlabel tempLabel;
2358 BOOL ok;
2359
2360 check( inMDNS );
2361
2362 // Set up the nice name.
2363 tempString[ 0 ] = '\0';
2364
2365 // use the hostname of the machine
2366 tempStringLen = sizeof( tempString );
2367 ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
2368 err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
2369 check_noerr( err );
2370
2371 // if we can't get the hostname
2372 if( err || ( tempString[ 0 ] == '\0' ) )
2373 {
2374 // Invalidate name so fall back to a default name.
2375
2376 strcpy( tempString, kMDNSDefaultName );
2377 }
2378
2379 tempString[ sizeof( tempString ) - 1 ] = '\0';
2380 tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
2381 memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
2382
2383 // Set up the host name.
2384
2385 ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
2386 if( inMDNS->hostlabel.c[ 0 ] == 0 )
2387 {
2388 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2389
2390 MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
2391 }
2392
2393 check( inMDNS->hostlabel.c[ 0 ] != 0 );
2394
2395 mDNS_SetFQDN( inMDNS );
2396
2397 dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
2398
2399 return( err );
2400}
2401
2402//===========================================================================================================================
2403// SetupName
2404//===========================================================================================================================
2405
2406mDNSlocal mStatus SetupName( mDNS * const inMDNS )
2407{
2408 mStatus err = 0;
2409
2410 check( inMDNS );
2411
2412 err = SetupNiceName( inMDNS );
2413 check_noerr( err );
2414
2415 err = SetupHostName( inMDNS );
2416 check_noerr( err );
2417
2418 return err;
2419}
2420
2421
2422//===========================================================================================================================
2423// SetupInterfaceList
2424//===========================================================================================================================
2425
2426mStatus SetupInterfaceList( mDNS * const inMDNS )
2427{
2428 mStatus err;
2429 mDNSInterfaceData ** next;
2430 mDNSInterfaceData * ifd;
2431 struct ifaddrs * addrs;
2432 struct ifaddrs * p;
2433 struct ifaddrs * loopbackv4;
2434 struct ifaddrs * loopbackv6;
2435 u_int flagMask;
2436 u_int flagTest;
2437 mDNSBool foundv4;
2438 mDNSBool foundv6;
2439 mDNSBool foundUnicastSock4DestAddr;
2440 mDNSBool foundUnicastSock6DestAddr;
2441
2442 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
2443 check( inMDNS );
2444 check( inMDNS->p );
2445
2446 inMDNS->p->registeredLoopback4 = mDNSfalse;
2447 inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
2448 addrs = NULL;
2449 foundv4 = mDNSfalse;
2450 foundv6 = mDNSfalse;
2451 foundUnicastSock4DestAddr = mDNSfalse;
2452 foundUnicastSock6DestAddr = mDNSfalse;
2453
2454 // Tear down any existing interfaces that may be set up.
2455
2456 TearDownInterfaceList( inMDNS );
2457
2458 // Set up the name of this machine.
2459
2460 err = SetupName( inMDNS );
2461 check_noerr( err );
2462
2463 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2464 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2465
2466 err = getifaddrs( &addrs );
2467 require_noerr( err, exit );
2468
2469 loopbackv4 = NULL;
2470 loopbackv6 = NULL;
2471 next = &inMDNS->p->interfaceList;
2472
2473 flagMask = IFF_UP | IFF_MULTICAST;
2474 flagTest = IFF_UP | IFF_MULTICAST;
2475
2476#if( MDNS_WINDOWS_ENABLE_IPV4 )
2477 for( p = addrs; p; p = p->ifa_next )
2478 {
2479 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2480 {
2481 continue;
2482 }
2483 if( p->ifa_flags & IFF_LOOPBACK )
2484 {
2485 if( !loopbackv4 )
2486 {
2487 loopbackv4 = p;
2488 }
2489 continue;
2490 }
2491 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2492 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
2493
2494 err = SetupInterface( inMDNS, p, &ifd );
2495 require_noerr( err, exit );
2496
2497 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2498 // register him, but we also want to note that we haven't found a v4 interface
2499 // so that we register loopback so same host operations work
2500
2501 if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
2502 {
2503 foundv4 = mDNStrue;
2504 }
2505
2506 if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
2507 {
2508 inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
2509 }
2510
2511 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2512 // of determing the destination address of a packet that is sent to us.
2513 // For multicast packets, that's easy to determine. But for the unicast
2514 // sockets, we'll fake it by taking the address of the first interface
2515 // that is successfully setup.
2516
2517 if ( !foundUnicastSock4DestAddr )
2518 {
2519 inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
2520 foundUnicastSock4DestAddr = TRUE;
2521 }
2522
2523 *next = ifd;
2524 next = &ifd->next;
2525 ++inMDNS->p->interfaceCount;
2526 }
2527#endif
2528
2529 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2530
2531#if( MDNS_WINDOWS_ENABLE_IPV6 )
2532 for( p = addrs; p; p = p->ifa_next )
2533 {
2534 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2535 {
2536 continue;
2537 }
2538 if( p->ifa_flags & IFF_LOOPBACK )
2539 {
2540 if( !loopbackv6 )
2541 {
2542 loopbackv6 = p;
2543 }
2544 continue;
2545 }
2546 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2547 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
2548
2549 err = SetupInterface( inMDNS, p, &ifd );
2550 require_noerr( err, exit );
2551
2552 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2553 // register him, but we also want to note that we haven't found a v4 interface
2554 // so that we register loopback so same host operations work
2555
2556 if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
2557 {
2558 foundv6 = mDNStrue;
2559 }
2560
2561 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2562 // of determing the destination address of a packet that is sent to us.
2563 // For multicast packets, that's easy to determine. But for the unicast
2564 // sockets, we'll fake it by taking the address of the first interface
2565 // that is successfully setup.
2566
2567 if ( !foundUnicastSock6DestAddr )
2568 {
2569 inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
2570 foundUnicastSock6DestAddr = TRUE;
2571 }
2572
2573 *next = ifd;
2574 next = &ifd->next;
2575 ++inMDNS->p->interfaceCount;
2576 }
2577#endif
2578
2579 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2580
2581#if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2582
2583 flagMask |= IFF_LOOPBACK;
2584 flagTest |= IFF_LOOPBACK;
2585
2586 for( p = addrs; p; p = p->ifa_next )
2587 {
2588 if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2589 {
2590 continue;
2591 }
2592 if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
2593 {
2594 continue;
2595 }
2596
2597 v4loopback = p;
2598 break;
2599 }
2600
2601#endif
2602
2603 if ( !foundv4 && loopbackv4 )
2604 {
2605 dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2606 loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
2607
2608 err = SetupInterface( inMDNS, loopbackv4, &ifd );
2609 require_noerr( err, exit );
2610
2611 inMDNS->p->registeredLoopback4 = mDNStrue;
2612
2613#if( MDNS_WINDOWS_ENABLE_IPV4 )
2614
2615 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2616 // of determing the destination address of a packet that is sent to us.
2617 // For multicast packets, that's easy to determine. But for the unicast
2618 // sockets, we'll fake it by taking the address of the first interface
2619 // that is successfully setup.
2620
2621 if ( !foundUnicastSock4DestAddr )
2622 {
2623 inMDNS->p->unicastSock4.addr = ifd->sock.addr;
2624 foundUnicastSock4DestAddr = TRUE;
2625 }
2626#endif
2627
2628 *next = ifd;
2629 next = &ifd->next;
2630 ++inMDNS->p->interfaceCount;
2631 }
2632
2633 if ( !foundv6 && loopbackv6 )
2634 {
2635 dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2636 loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
2637
2638 err = SetupInterface( inMDNS, loopbackv6, &ifd );
2639 require_noerr( err, exit );
2640
2641#if( MDNS_WINDOWS_ENABLE_IPV6 )
2642
2643 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2644 // of determing the destination address of a packet that is sent to us.
2645 // For multicast packets, that's easy to determine. But for the unicast
2646 // sockets, we'll fake it by taking the address of the first interface
2647 // that is successfully setup.
2648
2649 if ( !foundUnicastSock6DestAddr )
2650 {
2651 inMDNS->p->unicastSock6.addr = ifd->sock.addr;
2652 foundUnicastSock6DestAddr = TRUE;
2653 }
2654#endif
2655
2656 *next = ifd;
2657 next = &ifd->next;
2658 ++inMDNS->p->interfaceCount;
2659 }
2660
2661 CheckFileShares( inMDNS );
2662
2663exit:
2664 if( err )
2665 {
2666 TearDownInterfaceList( inMDNS );
2667 }
2668 if( addrs )
2669 {
2670 freeifaddrs( addrs );
2671 }
2672 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
2673 return( err );
2674}
2675
2676//===========================================================================================================================
2677// TearDownInterfaceList
2678//===========================================================================================================================
2679
2680mStatus TearDownInterfaceList( mDNS * const inMDNS )
2681{
2682 mDNSInterfaceData ** p;
2683 mDNSInterfaceData * ifd;
2684
2685 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
2686 check( inMDNS );
2687 check( inMDNS->p );
2688
2689 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2690 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2691 // so that remove events that occur after an interface goes away can still report the correct interface.
2692
2693 p = &inMDNS->p->inactiveInterfaceList;
2694 while( *p )
2695 {
2696 ifd = *p;
2697 if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
2698 {
2699 p = &ifd->next;
2700 continue;
2701 }
2702
2703 dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
2704 *p = ifd->next;
2705
2706 QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
2707 }
2708
2709 // Tear down all the interfaces.
2710
2711 while( inMDNS->p->interfaceList )
2712 {
2713 ifd = inMDNS->p->interfaceList;
2714 inMDNS->p->interfaceList = ifd->next;
2715
2716 TearDownInterface( inMDNS, ifd );
2717 }
2718 inMDNS->p->interfaceCount = 0;
2719
2720 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
2721 return( mStatus_NoError );
2722}
2723
2724//===========================================================================================================================
2725// SetupInterface
2726//===========================================================================================================================
2727
2728mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
2729{
2730 mDNSInterfaceData * ifd;
2731 mDNSInterfaceData * p;
2732 mStatus err;
2733
2734 ifd = NULL;
2735 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
2736 check( inMDNS );
2737 check( inMDNS->p );
2738 check( inIFA );
2739 check( inIFA->ifa_addr );
2740 check( outIFD );
2741
2742 // Allocate memory for the interface and initialize it.
2743
2744 ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
2745 require_action( ifd, exit, err = mStatus_NoMemoryErr );
2746 ifd->sock.fd = kInvalidSocketRef;
2747 ifd->sock.overlapped.pending = FALSE;
2748 ifd->sock.ifd = ifd;
2749 ifd->sock.next = NULL;
2750 ifd->sock.m = inMDNS;
2751 ifd->index = inIFA->ifa_extra.index;
2752 ifd->scopeID = inIFA->ifa_extra.index;
2753 check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
2754 strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
2755 ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
2756
2757 strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
2758 ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
2759
2760 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2761 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2762 // on a large configured network, which means there's a good chance that most or all the other devices on that
2763 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2764 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2765 // devices on a large configured network, so we are willing to make that sacrifice.
2766
2767 ifd->interfaceInfo.McastTxRx = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
2768 ifd->interfaceInfo.InterfaceID = NULL;
2769
2770 for( p = inMDNS->p->interfaceList; p; p = p->next )
2771 {
2772 if ( strcmp( p->name, ifd->name ) == 0 )
2773 {
2774 if (!ifd->interfaceInfo.InterfaceID)
2775 {
2776 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) p;
2777 }
2778
2779 if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
2780 ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
2781 ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
2782 {
2783 ifd->interfaceInfo.McastTxRx = mDNSfalse;
2784 }
2785
2786 break;
2787 }
2788 }
2789
2790 if ( !ifd->interfaceInfo.InterfaceID )
2791 {
2792 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
2793 }
2794
2795 // Set up a socket for this interface (if needed).
2796
2797 if( ifd->interfaceInfo.McastTxRx )
2798 {
2799 DWORD size;
2800
2801 err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
2802 require_noerr( err, exit );
2803 ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
2804 ifd->sock.port = MulticastDNSPort;
2805
2806 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2807
2808 err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
2809
2810 if ( err )
2811 {
2812 ifd->sock.recvMsgPtr = NULL;
2813 }
2814 }
2815
2816 if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
2817 {
2818 inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
2819 }
2820
2821 ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
2822
2823 // Register this interface with mDNS.
2824
2825 err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
2826 require_noerr( err, exit );
2827
2828 err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
2829 require_noerr( err, exit );
2830
2831 memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
2832
2833 ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
2834
2835 if ( ifd->sock.fd != kInvalidSocketRef )
2836 {
2837 err = UDPBeginRecv( &ifd->sock );
2838 require_noerr( err, exit );
2839 }
2840
2841 err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
2842 require_noerr( err, exit );
2843 ifd->hostRegistered = mDNStrue;
2844
2845 dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
2846
2847 // Success!
2848
2849 *outIFD = ifd;
2850 ifd = NULL;
2851
2852exit:
2853
2854 if( ifd )
2855 {
2856 TearDownInterface( inMDNS, ifd );
2857 }
2858 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
2859 return( err );
2860}
2861
2862//===========================================================================================================================
2863// TearDownInterface
2864//===========================================================================================================================
2865
2866mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
2867{
2868 check( inMDNS );
2869 check( inIFD );
2870
2871 // Deregister this interface with mDNS.
2872
2873 dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
2874
2875 if( inIFD->hostRegistered )
2876 {
2877 inIFD->hostRegistered = mDNSfalse;
2878 mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
2879 }
2880
2881 // Tear down the multicast socket.
2882
2883 UDPCloseSocket( &inIFD->sock );
2884
2885 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2886 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2887
2888 if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
2889 {
2890 inIFD->next = inMDNS->p->inactiveInterfaceList;
2891 inMDNS->p->inactiveInterfaceList = inIFD;
2892 dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
2893 }
2894 else
2895 {
2896 dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
2897 QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
2898 }
2899
2900 return( mStatus_NoError );
2901}
2902
2903mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
2904{
2905 free( inIFD );
2906}
2907
2908//===========================================================================================================================
2909// SetupSocket
2910//===========================================================================================================================
2911
2912mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef )
2913{
2914 mStatus err;
2915 SocketRef sock;
2916 int option;
2917 DWORD bytesReturned = 0;
2918 BOOL behavior = FALSE;
2919
2920 DEBUG_UNUSED( inMDNS );
2921
2922 dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
2923 check( inMDNS );
2924 check( outSocketRef );
2925
2926 // Set up an IPv4 or IPv6 UDP socket.
2927
2928 sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
2929 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2930 require_noerr( err, exit );
2931
2932 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2933 // if we're creating a multicast socket
2934
2935 if ( port.NotAnInteger )
2936 {
2937 option = 1;
2938 err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
2939 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2940 }
2941
2942 // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
2943 //
2944 // Not sure why, but the default behavior for sockets is to behave incorrectly
2945 // when using them in Overlapped I/O mode on XP. According to MSDN:
2946 //
2947 // SIO_UDP_CONNRESET (opcode setting: I, T==3)
2948 // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
2949 // Set to FALSE to disable reporting.
2950 //
2951 // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
2952 // messages were being sent to us after we sent out packets to a multicast address. This is clearly
2953 // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
2954 // will no longer receive any packets from that socket, which is not harmless. This behavior is only
2955 // seen on XP.
2956 //
2957 // So we turn off port unreachable reporting to make sure our sockets that are reading
2958 // multicast packets function correctly under all circumstances.
2959
2960 err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
2961 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2962
2963 if( inAddr->sa_family == AF_INET )
2964 {
2965 mDNSv4Addr ipv4;
2966 struct sockaddr_in sa4;
2967 struct ip_mreq mreqv4;
2968
2969 // Bind the socket to the desired port
2970
2971 ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
2972 mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
2973 sa4.sin_family = AF_INET;
2974 sa4.sin_port = port.NotAnInteger;
2975 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
2976
2977 err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
2978 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
2979
2980 // Turn on option to receive destination addresses and receiving interface.
2981
2982 option = 1;
2983 err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
2984 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2985
2986 if (port.NotAnInteger)
2987 {
2988 // Join the all-DNS multicast group so we receive Multicast DNS packets
2989
2990 mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
2991 mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
2992 err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
2993 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2994
2995 // Specify the interface to send multicast packets on this socket.
2996
2997 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
2998 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
2999 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3000
3001 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3002
3003 option = 1;
3004 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
3005 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3006 }
3007
3008 // Send unicast packets with TTL 255 (helps against spoofing).
3009
3010 option = 255;
3011 err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
3012 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3013
3014 // Send multicast packets with TTL 255 (helps against spoofing).
3015
3016 option = 255;
3017 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
3018 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3019
3020 }
3021 else if( inAddr->sa_family == AF_INET6 )
3022 {
3023 struct sockaddr_in6 * sa6p;
3024 struct sockaddr_in6 sa6;
3025 struct ipv6_mreq mreqv6;
3026
3027 sa6p = (struct sockaddr_in6 *) inAddr;
3028
3029 // Bind the socket to the desired port
3030
3031 mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
3032 sa6.sin6_family = AF_INET6;
3033 sa6.sin6_port = port.NotAnInteger;
3034 sa6.sin6_flowinfo = 0;
3035 sa6.sin6_addr = sa6p->sin6_addr;
3036 sa6.sin6_scope_id = sa6p->sin6_scope_id;
3037
3038 err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
3039 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
3040
3041 // Turn on option to receive destination addresses and receiving interface.
3042
3043 option = 1;
3044 err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
3045 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3046
3047 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
3048 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
3049 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
3050
3051 #if( defined( IPV6_V6ONLY ) )
3052 option = 1;
3053 err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
3054 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3055 #endif
3056
3057 if ( port.NotAnInteger )
3058 {
3059 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3060
3061 mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
3062 mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
3063 err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
3064 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3065
3066 // Specify the interface to send multicast packets on this socket.
3067
3068 option = (int) sa6p->sin6_scope_id;
3069 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
3070 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3071
3072 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3073
3074 option = 1;
3075 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
3076 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3077 }
3078
3079 // Send unicast packets with TTL 255 (helps against spoofing).
3080
3081 option = 255;
3082 err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
3083 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3084
3085 // Send multicast packets with TTL 255 (helps against spoofing).
3086
3087 option = 255;
3088 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
3089 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3090 }
3091 else
3092 {
3093 dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
3094 err = kUnsupportedErr;
3095 goto exit;
3096 }
3097
3098 // Success!
3099
3100 *outSocketRef = sock;
3101 sock = kInvalidSocketRef;
3102 err = mStatus_NoError;
3103
3104exit:
3105 if( IsValidSocket( sock ) )
3106 {
3107 close_compat( sock );
3108 }
3109 return( err );
3110}
3111
3112//===========================================================================================================================
3113// SetupSocket
3114//===========================================================================================================================
3115
3116mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
3117{
3118 mStatus err;
3119
3120 check( inSA );
3121 check( outIP );
3122
3123 if( inSA->sa_family == AF_INET )
3124 {
3125 struct sockaddr_in * sa4;
3126
3127 sa4 = (struct sockaddr_in *) inSA;
3128 outIP->type = mDNSAddrType_IPv4;
3129 outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
3130 if( outPort )
3131 {
3132 outPort->NotAnInteger = sa4->sin_port;
3133 }
3134 err = mStatus_NoError;
3135 }
3136 else if( inSA->sa_family == AF_INET6 )
3137 {
3138 struct sockaddr_in6 * sa6;
3139
3140 sa6 = (struct sockaddr_in6 *) inSA;
3141 outIP->type = mDNSAddrType_IPv6;
3142 outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
3143 if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
3144 {
3145 outIP->ip.v6.w[ 1 ] = 0;
3146 }
3147 if( outPort )
3148 {
3149 outPort->NotAnInteger = sa6->sin6_port;
3150 }
3151 err = mStatus_NoError;
3152 }
3153 else
3154 {
3155 dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
3156 err = mStatus_BadParamErr;
3157 }
3158 return( err );
3159}
3160
3161
3162#if 0
3163#pragma mark -
3164#endif
3165
3166//===========================================================================================================================
3167// UDPBeginRecv
3168//===========================================================================================================================
3169
3170mDNSlocal OSStatus UDPBeginRecv( UDPSocket * sock )
3171{
3172 DWORD size;
3173 DWORD numTries;
3174 mStatus err;
3175
3176 dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
3177
3178 require_action( sock != NULL, exit, err = mStatus_BadStateErr );
3179 check( !sock->overlapped.pending );
3180
3181 // Initialize the buffer structure
3182
3183 sock->overlapped.wbuf.buf = (char *) &sock->packet;
3184 sock->overlapped.wbuf.len = (u_long) sizeof( sock->packet );
3185 sock->srcAddrLen = sizeof( sock->srcAddr );
3186
3187 // Initialize the overlapped structure
3188
3189 ZeroMemory( &sock->overlapped.data, sizeof( OVERLAPPED ) );
3190 sock->overlapped.data.hEvent = sock;
3191
3192 numTries = 0;
3193
3194 do
3195 {
3196 if ( sock->recvMsgPtr )
3197 {
3198 sock->wmsg.name = ( LPSOCKADDR ) &sock->srcAddr;
3199 sock->wmsg.namelen = sock->srcAddrLen;
3200 sock->wmsg.lpBuffers = &sock->overlapped.wbuf;
3201 sock->wmsg.dwBufferCount = 1;
3202 sock->wmsg.Control.buf = ( CHAR* ) sock->controlBuffer;
3203 sock->wmsg.Control.len = sizeof( sock->controlBuffer );
3204 sock->wmsg.dwFlags = 0;
3205
3206 err = sock->recvMsgPtr( sock->fd, &sock->wmsg, &size, &sock->overlapped.data, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
3207 err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), (OSStatus) WSAGetLastError(), kUnknownErr );
3208
3209 // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
3210 //
3211 // There seems to be a bug in some network device drivers that involves calling WSARecvMsg() in
3212 // overlapped i/o mode. Although all the parameters to WSARecvMsg() are correct, it returns a
3213 // WSAEFAULT error code when there is no actual error. We have found experientially that falling
3214 // back to using WSARecvFrom() when this happens will work correctly.
3215
3216 if ( err == WSAEFAULT ) sock->recvMsgPtr = NULL;
3217 }
3218 else
3219 {
3220 DWORD flags = 0;
3221
3222 err = WSARecvFrom( sock->fd, &sock->overlapped.wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sock->srcAddr, &sock->srcAddrLen, &sock->overlapped.data, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
3223 err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
3224 }
3225
3226 // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
3227 //
3228 // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
3229 // send operation resulted in an ICMP "Port Unreachable" message."
3230 //
3231 // Because this is the case, we want to ignore this error and try again. Just in case
3232 // this is some kind of pathological condition, we'll break out of the retry loop
3233 // after 100 iterations
3234
3235 require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
3236 }
3237 while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
3238
3239 sock->overlapped.pending = TRUE;
3240
3241exit:
3242
3243 if ( err )
3244 {
3245 LogMsg( "WSARecvMsg failed (%d)\n", err );
3246 }
3247
3248 return err;
3249}
3250
3251
3252//===========================================================================================================================
3253// UDPEndRecv
3254//===========================================================================================================================
3255
3256mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
3257{
3258 UDPSocket * sock = NULL;
3259
3260 ( void ) flags;
3261
3262 dlog( kDebugLevelChatty, DEBUG_NAME "%s: err = %d, bytesTransferred = %d\n", __ROUTINE__, err, bytesTransferred );
3263 require_action_quiet( err != WSA_OPERATION_ABORTED, exit, err = ( DWORD ) kUnknownErr );
3264 require_noerr( err, exit );
3265 sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
3266 require_action( sock != NULL, exit, err = ( DWORD ) kUnknownErr );
3267 dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, sock->fd );
3268 sock->overlapped.error = err;
3269 sock->overlapped.bytesTransferred = bytesTransferred;
3270 check( sock->overlapped.pending );
3271 sock->overlapped.pending = FALSE;
3272
3273 // Translate the source of this packet into mDNS data types
3274
3275 SockAddrToMDNSAddr( (struct sockaddr *) &sock->srcAddr, &sock->overlapped.srcAddr, &sock->overlapped.srcPort );
3276
3277 // Initialize the destination of this packet. Just in case
3278 // we can't determine this info because we couldn't call
3279 // WSARecvMsg (recvMsgPtr)
3280
3281 sock->overlapped.dstAddr = sock->addr;
3282 sock->overlapped.dstPort = sock->port;
3283
3284 if ( sock->recvMsgPtr )
3285 {
3286 LPWSACMSGHDR header;
3287 LPWSACMSGHDR last = NULL;
3288 int count = 0;
3289
3290 // Parse the control information. Reject packets received on the wrong interface.
3291
3292 // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
3293 //
3294 // There seems to be an interaction between Bullguard and this next bit of code.
3295 // When a user's machine is running Bullguard, the control information that is
3296 // returned is corrupted, and the code would go into an infinite loop. We'll add
3297 // two bits of defensive coding here. The first will check that each pointer to
3298 // the LPWSACMSGHDR that is returned in the for loop is different than the last.
3299 // This fixes the problem with Bullguard. The second will break out of this loop
3300 // after 100 iterations, just in case the corruption isn't caught by the first
3301 // check.
3302
3303 for ( header = WSA_CMSG_FIRSTHDR( &sock->wmsg ); header; header = WSA_CMSG_NXTHDR( &sock->wmsg, header ) )
3304 {
3305 if ( ( header != last ) && ( ++count < 100 ) )
3306 {
3307 last = header;
3308
3309 if ( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
3310 {
3311 IN_PKTINFO * ipv4PacketInfo;
3312
3313 ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
3314
3315 if ( sock->ifd != NULL )
3316 {
3317 require_action( ipv4PacketInfo->ipi_ifindex == sock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
3318 }
3319
3320 sock->overlapped.dstAddr.type = mDNSAddrType_IPv4;
3321 sock->overlapped.dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
3322 }
3323 else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
3324 {
3325 IN6_PKTINFO * ipv6PacketInfo;
3326
3327 ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
3328
3329 if ( sock->ifd != NULL )
3330 {
3331 require_action( ipv6PacketInfo->ipi6_ifindex == ( sock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
3332 }
3333
3334 sock->overlapped.dstAddr.type = mDNSAddrType_IPv6;
3335 sock->overlapped.dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
3336 }
3337 }
3338 else
3339 {
3340 static BOOL loggedMessage = FALSE;
3341
3342 if ( !loggedMessage )
3343 {
3344 LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
3345 loggedMessage = TRUE;
3346 }
3347
3348 break;
3349 }
3350 }
3351 }
3352
3353 dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
3354 dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", bytesTransferred );
3355 dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &sock->overlapped.srcAddr, ntohs( sock->overlapped.srcPort.NotAnInteger ) );
3356 dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &sock->overlapped.dstAddr, ntohs( sock->overlapped.dstPort.NotAnInteger ) );
3357
3358 if ( sock->ifd != NULL )
3359 {
3360 dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &sock->ifd->interfaceInfo.ip, sock->ifd->index );
3361 }
3362
3363 dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
3364
3365 // Queue this socket
3366
3367 AddToTail( &gUDPDispatchableSockets, sock );
3368
3369exit:
3370
3371 return;
3372}
3373
3374
3375//===========================================================================================================================
3376// InterfaceListDidChange
3377//===========================================================================================================================
3378void InterfaceListDidChange( mDNS * const inMDNS )
3379{
3380 mStatus err;
3381
3382 dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
3383 check( inMDNS );
3384
3385 // Tear down the existing interfaces and set up new ones using the new IP info.
3386
3387 err = TearDownInterfaceList( inMDNS );
3388 check_noerr( err );
3389
3390 err = SetupInterfaceList( inMDNS );
3391 check_noerr( err );
3392
3393 err = uDNS_SetupDNSConfig( inMDNS );
3394 check_noerr( err );
3395
3396 // Inform clients of the change.
3397
3398 mDNS_ConfigChanged(inMDNS);
3399
3400 // Force mDNS to update.
3401
3402 mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
3403}
3404
3405
3406//===========================================================================================================================
3407// ComputerDescriptionDidChange
3408//===========================================================================================================================
3409void ComputerDescriptionDidChange( mDNS * const inMDNS )
3410{
3411 dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
3412 check( inMDNS );
3413
3414 // redo the names
3415 SetupNiceName( inMDNS );
3416}
3417
3418
3419//===========================================================================================================================
3420// TCPIPConfigDidChange
3421//===========================================================================================================================
3422void TCPIPConfigDidChange( mDNS * const inMDNS )
3423{
3424 mStatus err;
3425
3426 dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
3427 check( inMDNS );
3428
3429 err = uDNS_SetupDNSConfig( inMDNS );
3430 check_noerr( err );
3431}
3432
3433
3434//===========================================================================================================================
3435// DynDNSConfigDidChange
3436//===========================================================================================================================
3437void DynDNSConfigDidChange( mDNS * const inMDNS )
3438{
3439 mStatus err;
3440
3441 dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
3442 check( inMDNS );
3443
3444 SetDomainSecrets( inMDNS );
3445
3446 err = uDNS_SetupDNSConfig( inMDNS );
3447 check_noerr( err );
3448}
3449
3450
3451//===========================================================================================================================
3452// FileSharingDidChange
3453//===========================================================================================================================
3454void FileSharingDidChange( mDNS * const inMDNS )
3455{
3456 dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
3457 check( inMDNS );
3458
3459 CheckFileShares( inMDNS );
3460}
3461
3462
3463//===========================================================================================================================
3464// FilewallDidChange
3465//===========================================================================================================================
3466void FirewallDidChange( mDNS * const inMDNS )
3467{
3468 dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
3469 check( inMDNS );
3470
3471 CheckFileShares( inMDNS );
3472}
3473
3474
3475#if 0
3476#pragma mark -
3477#pragma mark == Utilities ==
3478#endif
3479
3480//===========================================================================================================================
3481// getifaddrs
3482//===========================================================================================================================
3483
3484mDNSlocal int getifaddrs( struct ifaddrs **outAddrs )
3485{
3486 int err;
3487
3488#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3489
3490 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3491 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3492
3493 if( !gIPHelperLibraryInstance )
3494 {
3495 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
3496 if( gIPHelperLibraryInstance )
3497 {
3498 gGetAdaptersAddressesFunctionPtr =
3499 (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
3500 if( !gGetAdaptersAddressesFunctionPtr )
3501 {
3502 BOOL ok;
3503
3504 ok = FreeLibrary( gIPHelperLibraryInstance );
3505 check_translated_errno( ok, GetLastError(), kUnknownErr );
3506 gIPHelperLibraryInstance = NULL;
3507 }
3508 }
3509 }
3510
3511 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3512 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
3513 // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
3514
3515 if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
3516 {
3517 err = getifaddrs_ipv4( outAddrs );
3518 require_noerr( err, exit );
3519 }
3520
3521#else
3522
3523 err = getifaddrs_ipv4( outAddrs );
3524 require_noerr( err, exit );
3525
3526#endif
3527
3528exit:
3529 return( err );
3530}
3531
3532#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3533//===========================================================================================================================
3534// getifaddrs_ipv6
3535//===========================================================================================================================
3536
3537mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
3538{
3539 DWORD err;
3540 int i;
3541 DWORD flags;
3542 struct ifaddrs * head;
3543 struct ifaddrs ** next;
3544 IP_ADAPTER_ADDRESSES * iaaList;
3545 ULONG iaaListSize;
3546 IP_ADAPTER_ADDRESSES * iaa;
3547 size_t size;
3548 struct ifaddrs * ifa;
3549
3550 check( gGetAdaptersAddressesFunctionPtr );
3551
3552 head = NULL;
3553 next = &head;
3554 iaaList = NULL;
3555
3556 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3557 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3558 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3559
3560 flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
3561 i = 0;
3562 for( ;; )
3563 {
3564 iaaListSize = 0;
3565 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
3566 check( err == ERROR_BUFFER_OVERFLOW );
3567 check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
3568
3569 iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
3570 require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
3571
3572 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
3573 if( err == ERROR_SUCCESS ) break;
3574
3575 free( iaaList );
3576 iaaList = NULL;
3577 ++i;
3578 require( i < 100, exit );
3579 dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
3580 }
3581
3582 for( iaa = iaaList; iaa; iaa = iaa->Next )
3583 {
3584 int addrIndex;
3585 IP_ADAPTER_UNICAST_ADDRESS * addr;
3586 DWORD ipv6IfIndex;
3587 IP_ADAPTER_PREFIX * firstPrefix;
3588
3589 if( iaa->IfIndex > 0xFFFFFF )
3590 {
3591 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
3592 }
3593 if( iaa->Ipv6IfIndex > 0xFF )
3594 {
3595 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
3596 }
3597
3598 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3599 // following code to crash when iterating through the prefix list. This seems
3600 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3601 // This shouldn't happen according to Microsoft docs which states:
3602 //
3603 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3604 //
3605 // So the data structure seems to be corrupted when we return from
3606 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3607 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3608 // modify iaa to have the correct values.
3609
3610 if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
3611 {
3612 ipv6IfIndex = iaa->Ipv6IfIndex;
3613 firstPrefix = iaa->FirstPrefix;
3614 }
3615 else
3616 {
3617 ipv6IfIndex = 0;
3618 firstPrefix = NULL;
3619 }
3620
3621 // Skip pseudo and tunnel interfaces.
3622
3623 if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
3624 {
3625 continue;
3626 }
3627
3628 // Add each address as a separate interface to emulate the way getifaddrs works.
3629
3630 for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
3631 {
3632 int family;
3633 int prefixIndex;
3634 IP_ADAPTER_PREFIX * prefix;
3635 ULONG prefixLength;
3636 uint32_t ipv4Index;
3637 struct sockaddr_in ipv4Netmask;
3638
3639 family = addr->Address.lpSockaddr->sa_family;
3640 if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
3641
3642 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3643 // Seems as if the problem here is a buggy implementation of some network interface
3644 // driver. It is reporting that is has a link-local address when it is actually
3645 // disconnected. This was causing a problem in AddressToIndexAndMask.
3646 // The solution is to call AddressToIndexAndMask first, and if unable to lookup
3647 // the address, to ignore that address.
3648
3649 ipv4Index = 0;
3650 memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
3651
3652 if ( family == AF_INET )
3653 {
3654 err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
3655
3656 if ( err )
3657 {
3658 err = 0;
3659 continue;
3660 }
3661 }
3662
3663 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
3664 require_action( ifa, exit, err = WSAENOBUFS );
3665
3666 *next = ifa;
3667 next = &ifa->ifa_next;
3668
3669 // Get the name.
3670
3671 size = strlen( iaa->AdapterName ) + 1;
3672 ifa->ifa_name = (char *) malloc( size );
3673 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
3674 memcpy( ifa->ifa_name, iaa->AdapterName, size );
3675
3676 // Get interface flags.
3677
3678 ifa->ifa_flags = 0;
3679 if( iaa->OperStatus == IfOperStatusUp ) ifa->ifa_flags |= IFF_UP;
3680 if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK ) ifa->ifa_flags |= IFF_LOOPBACK;
3681 else if ( IsPointToPoint( addr ) ) ifa->ifa_flags |= IFF_POINTTOPOINT;
3682 if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
3683
3684
3685 // <rdar://problem/4045657> Interface index being returned is 512
3686 //
3687 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
3688 // This code used to shift the IPv4 index up to ensure uniqueness between
3689 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
3690 // then see interface indexes passed back that don't correspond to anything
3691 // that is seen in Win32 APIs or command line tools like "route". As a relatively
3692 // small percentage of developers are actively using IPv6, it seems to
3693 // make sense to make our use of IPv4 as confusion free as possible.
3694 // So now, IPv6 interface indexes will be shifted up by a
3695 // constant value which will serve to uniquely identify them, and we will
3696 // leave IPv4 interface indexes unmodified.
3697
3698 switch( family )
3699 {
3700 case AF_INET: ifa->ifa_extra.index = iaa->IfIndex; break;
3701 case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase; break;
3702 default: break;
3703 }
3704
3705 // Get lease lifetime
3706
3707 if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
3708 {
3709 ifa->ifa_dhcpEnabled = TRUE;
3710 ifa->ifa_dhcpLeaseExpires = time( NULL ) + addr->ValidLifetime;
3711 }
3712 else
3713 {
3714 ifa->ifa_dhcpEnabled = FALSE;
3715 ifa->ifa_dhcpLeaseExpires = 0;
3716 }
3717
3718 if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
3719 {
3720 memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
3721 }
3722
3723 // Because we don't get notified of womp changes, we're going to just assume
3724 // that all wired interfaces have it enabled. Before we go to sleep, we'll check
3725 // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
3726 // accordingly
3727
3728 ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
3729
3730 // Get address.
3731
3732 switch( family )
3733 {
3734 case AF_INET:
3735 case AF_INET6:
3736 ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
3737 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
3738 memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
3739 break;
3740
3741 default:
3742 break;
3743 }
3744 check( ifa->ifa_addr );
3745
3746 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
3747
3748 prefixLength = 0;
3749 for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next )
3750 {
3751 if( ( prefix->Address.lpSockaddr->sa_family == family ) && ( prefixIndex == addrIndex ) )
3752 {
3753 check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" );
3754 prefixLength = prefix->PrefixLength;
3755 break;
3756 }
3757 }
3758 switch( family )
3759 {
3760 case AF_INET:
3761 {
3762 struct sockaddr_in * sa4;
3763
3764 sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
3765 require_action( sa4, exit, err = WSAENOBUFS );
3766 sa4->sin_family = AF_INET;
3767 sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
3768
3769 dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
3770 ifa->ifa_netmask = (struct sockaddr *) sa4;
3771 break;
3772 }
3773
3774 case AF_INET6:
3775 {
3776 struct sockaddr_in6 * sa6;
3777 int len;
3778 int maskIndex;
3779 uint8_t maskByte;
3780
3781 require_action( prefixLength <= 128, exit, err = ERROR_INVALID_DATA );
3782
3783 sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
3784 require_action( sa6, exit, err = WSAENOBUFS );
3785 sa6->sin6_family = AF_INET6;
3786
3787 if( prefixLength == 0 )
3788 {
3789 dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__ );
3790 prefixLength = 128;
3791 }
3792 maskIndex = 0;
3793 for( len = (int) prefixLength; len > 0; len -= 8 )
3794 {
3795 if( len >= 8 ) maskByte = 0xFF;
3796 else maskByte = (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
3797 sa6->sin6_addr.s6_addr[ maskIndex++ ] = maskByte;
3798 }
3799 ifa->ifa_netmask = (struct sockaddr *) sa6;
3800 break;
3801 }
3802
3803 default:
3804 break;
3805 }
3806 }
3807 }
3808
3809 // Success!
3810
3811 if( outAddrs )
3812 {
3813 *outAddrs = head;
3814 head = NULL;
3815 }
3816 err = ERROR_SUCCESS;
3817
3818exit:
3819 if( head )
3820 {
3821 freeifaddrs( head );
3822 }
3823 if( iaaList )
3824 {
3825 free( iaaList );
3826 }
3827 return( (int) err );
3828}
3829
3830#endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
3831
3832//===========================================================================================================================
3833// getifaddrs_ipv4
3834//===========================================================================================================================
3835
3836mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
3837{
3838 int err;
3839 SOCKET sock;
3840 DWORD size;
3841 DWORD actualSize;
3842 INTERFACE_INFO * buffer;
3843 INTERFACE_INFO * tempBuffer;
3844 INTERFACE_INFO * ifInfo;
3845 int n;
3846 int i;
3847 struct ifaddrs * head;
3848 struct ifaddrs ** next;
3849 struct ifaddrs * ifa;
3850
3851 sock = INVALID_SOCKET;
3852 buffer = NULL;
3853 head = NULL;
3854 next = &head;
3855
3856 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
3857 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
3858 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
3859
3860 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
3861 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
3862 require_noerr( err, exit );
3863
3864 n = 0;
3865 size = 16 * sizeof( INTERFACE_INFO );
3866 for( ;; )
3867 {
3868 tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
3869 require_action( tempBuffer, exit, err = WSAENOBUFS );
3870 buffer = tempBuffer;
3871
3872 err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
3873 if( err == 0 )
3874 {
3875 break;
3876 }
3877
3878 ++n;
3879 require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
3880
3881 size += ( 16 * sizeof( INTERFACE_INFO ) );
3882 }
3883 check( actualSize <= size );
3884 check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
3885 n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
3886
3887 // Process the raw interface list and build a linked list of IPv4 interfaces.
3888
3889 for( i = 0; i < n; ++i )
3890 {
3891 uint32_t ifIndex;
3892 struct sockaddr_in netmask;
3893
3894 ifInfo = &buffer[ i ];
3895 if( ifInfo->iiAddress.Address.sa_family != AF_INET )
3896 {
3897 continue;
3898 }
3899
3900 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3901 // See comment in getifaddrs_ipv6
3902
3903 ifIndex = 0;
3904 memset( &netmask, 0, sizeof( netmask ) );
3905 err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
3906
3907 if ( err )
3908 {
3909 continue;
3910 }
3911
3912 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
3913 require_action( ifa, exit, err = WSAENOBUFS );
3914
3915 *next = ifa;
3916 next = &ifa->ifa_next;
3917
3918 // Get the name.
3919
3920 ifa->ifa_name = (char *) malloc( 16 );
3921 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
3922 sprintf( ifa->ifa_name, "%d", i + 1 );
3923
3924 // Get interface flags.
3925
3926 ifa->ifa_flags = (u_int) ifInfo->iiFlags;
3927
3928 // Get addresses.
3929
3930 if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
3931 {
3932 struct sockaddr_in * sa4;
3933
3934 sa4 = &ifInfo->iiAddress.AddressIn;
3935 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
3936 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
3937 memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
3938
3939 ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
3940 require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
3941
3942 // <rdar://problem/4076478> Service won't start on Win2K. The address
3943 // family field was not being initialized.
3944
3945 ifa->ifa_netmask->sa_family = AF_INET;
3946 ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
3947 ifa->ifa_extra.index = ifIndex;
3948 }
3949 else
3950 {
3951 // Emulate an interface index.
3952
3953 ifa->ifa_extra.index = (uint32_t)( i + 1 );
3954 }
3955 }
3956
3957 // Success!
3958
3959 if( outAddrs )
3960 {
3961 *outAddrs = head;
3962 head = NULL;
3963 }
3964 err = 0;
3965
3966exit:
3967
3968 if( head )
3969 {
3970 freeifaddrs( head );
3971 }
3972 if( buffer )
3973 {
3974 free( buffer );
3975 }
3976 if( sock != INVALID_SOCKET )
3977 {
3978 closesocket( sock );
3979 }
3980 return( err );
3981}
3982
3983//===========================================================================================================================
3984// freeifaddrs
3985//===========================================================================================================================
3986
3987mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
3988{
3989 struct ifaddrs * p;
3990 struct ifaddrs * q;
3991
3992 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
3993
3994 for( p = inIFAs; p; p = q )
3995 {
3996 q = p->ifa_next;
3997
3998 if( p->ifa_name )
3999 {
4000 free( p->ifa_name );
4001 p->ifa_name = NULL;
4002 }
4003 if( p->ifa_addr )
4004 {
4005 free( p->ifa_addr );
4006 p->ifa_addr = NULL;
4007 }
4008 if( p->ifa_netmask )
4009 {
4010 free( p->ifa_netmask );
4011 p->ifa_netmask = NULL;
4012 }
4013 if( p->ifa_broadaddr )
4014 {
4015 free( p->ifa_broadaddr );
4016 p->ifa_broadaddr = NULL;
4017 }
4018 if( p->ifa_dstaddr )
4019 {
4020 free( p->ifa_dstaddr );
4021 p->ifa_dstaddr = NULL;
4022 }
4023 if( p->ifa_data )
4024 {
4025 free( p->ifa_data );
4026 p->ifa_data = NULL;
4027 }
4028 free( p );
4029 }
4030}
4031
4032
4033//===========================================================================================================================
4034// GetPrimaryInterface
4035//===========================================================================================================================
4036
4037mDNSlocal DWORD
4038GetPrimaryInterface()
4039{
4040 PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
4041 DWORD dwSize = 0;
4042 BOOL bOrder = FALSE;
4043 OSStatus err;
4044 DWORD index = 0;
4045 DWORD metric = 0;
4046 unsigned long int i;
4047
4048 // Find out how big our buffer needs to be.
4049
4050 err = GetIpForwardTable(NULL, &dwSize, bOrder);
4051 require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
4052
4053 // Allocate the memory for the table
4054
4055 pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
4056 require_action( pIpForwardTable, exit, err = kNoMemoryErr );
4057
4058 // Now get the table.
4059
4060 err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
4061 require_noerr( err, exit );
4062
4063
4064 // Search for the row in the table we want.
4065
4066 for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
4067 {
4068 // Look for a default route
4069
4070 if ( pIpForwardTable->table[i].dwForwardDest == 0 )
4071 {
4072 if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
4073 {
4074 continue;
4075 }
4076
4077 index = pIpForwardTable->table[i].dwForwardIfIndex;
4078 metric = pIpForwardTable->table[i].dwForwardMetric1;
4079 }
4080 }
4081
4082exit:
4083
4084 if ( pIpForwardTable != NULL )
4085 {
4086 free( pIpForwardTable );
4087 }
4088
4089 return index;
4090}
4091
4092
4093//===========================================================================================================================
4094// AddressToIndexAndMask
4095//===========================================================================================================================
4096
4097mDNSlocal mStatus
4098AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask )
4099{
4100 // Before calling AddIPAddress we use GetIpAddrTable to get
4101 // an adapter to which we can add the IP.
4102
4103 PMIB_IPADDRTABLE pIPAddrTable = NULL;
4104 DWORD dwSize = 0;
4105 mStatus err = mStatus_UnknownErr;
4106 DWORD i;
4107
4108 // For now, this is only for IPv4 addresses. That is why we can safely cast
4109 // addr's to sockaddr_in.
4110
4111 require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
4112
4113 // Make an initial call to GetIpAddrTable to get the
4114 // necessary size into the dwSize variable
4115
4116 for ( i = 0; i < 100; i++ )
4117 {
4118 err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
4119
4120 if ( err != ERROR_INSUFFICIENT_BUFFER )
4121 {
4122 break;
4123 }
4124
4125 pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
4126 require_action( pIPAddrTable, exit, err = WSAENOBUFS );
4127 }
4128
4129 require_noerr( err, exit );
4130 err = mStatus_UnknownErr;
4131
4132 for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
4133 {
4134 if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
4135 {
4136 *ifIndex = pIPAddrTable->table[i].dwIndex;
4137 ( ( struct sockaddr_in*) mask )->sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
4138 err = mStatus_NoError;
4139 break;
4140 }
4141 }
4142
4143exit:
4144
4145 if ( pIPAddrTable )
4146 {
4147 free( pIPAddrTable );
4148 }
4149
4150 return err;
4151}
4152
4153
4154//===========================================================================================================================
4155// CanReceiveUnicast
4156//===========================================================================================================================
4157
4158mDNSlocal mDNSBool CanReceiveUnicast( void )
4159{
4160 mDNSBool ok;
4161 SocketRef sock;
4162 struct sockaddr_in addr;
4163
4164 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4165
4166 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
4167 check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
4168 ok = IsValidSocket( sock );
4169 if( ok )
4170 {
4171 mDNSPlatformMemZero( &addr, sizeof( addr ) );
4172 addr.sin_family = AF_INET;
4173 addr.sin_port = MulticastDNSPort.NotAnInteger;
4174 addr.sin_addr.s_addr = htonl( INADDR_ANY );
4175
4176 ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
4177 close_compat( sock );
4178 }
4179
4180 dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
4181 return( ok );
4182}
4183
4184
4185//===========================================================================================================================
4186// IsPointToPoint
4187//===========================================================================================================================
4188
4189mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
4190{
4191 struct ifaddrs * addrs = NULL;
4192 struct ifaddrs * p = NULL;
4193 OSStatus err;
4194 mDNSBool ret = mDNSfalse;
4195
4196 // For now, only works for IPv4 interfaces
4197
4198 if ( addr->Address.lpSockaddr->sa_family == AF_INET )
4199 {
4200 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4201
4202 err = getifaddrs_ipv4( &addrs );
4203 require_noerr( err, exit );
4204
4205 for ( p = addrs; p; p = p->ifa_next )
4206 {
4207 if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
4208 ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
4209 {
4210 ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
4211 break;
4212 }
4213 }
4214 }
4215
4216exit:
4217
4218 if ( addrs )
4219 {
4220 freeifaddrs( addrs );
4221 }
4222
4223 return ret;
4224}
4225
4226
4227//===========================================================================================================================
4228// GetWindowsVersionString
4229//===========================================================================================================================
4230
4231mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
4232{
4233#if( !defined( VER_PLATFORM_WIN32_CE ) )
4234 #define VER_PLATFORM_WIN32_CE 3
4235#endif
4236
4237 OSStatus err;
4238 OSVERSIONINFO osInfo;
4239 BOOL ok;
4240 const char * versionString;
4241 DWORD platformID;
4242 DWORD majorVersion;
4243 DWORD minorVersion;
4244 DWORD buildNumber;
4245
4246 versionString = "unknown Windows version";
4247
4248 osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
4249 ok = GetVersionEx( &osInfo );
4250 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
4251 require_noerr( err, exit );
4252
4253 platformID = osInfo.dwPlatformId;
4254 majorVersion = osInfo.dwMajorVersion;
4255 minorVersion = osInfo.dwMinorVersion;
4256 buildNumber = osInfo.dwBuildNumber & 0xFFFF;
4257
4258 if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
4259 {
4260 if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
4261 {
4262 versionString = "Windows 95";
4263 }
4264 else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
4265 {
4266 versionString = "Windows 95 SP1";
4267 }
4268 else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
4269 {
4270 versionString = "Windows 95 OSR2";
4271 }
4272 else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
4273 {
4274 versionString = "Windows 98";
4275 }
4276 else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
4277 {
4278 versionString = "Windows 98 SP1";
4279 }
4280 else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
4281 {
4282 versionString = "Windows 98 SE";
4283 }
4284 else if( minorVersion == 90 )
4285 {
4286 versionString = "Windows ME";
4287 }
4288 }
4289 else if( platformID == VER_PLATFORM_WIN32_NT )
4290 {
4291 if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
4292 {
4293 versionString = "Windows NT 3.51";
4294 }
4295 else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
4296 {
4297 versionString = "Windows NT 4";
4298 }
4299 else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
4300 {
4301 versionString = "Windows 2000";
4302 }
4303 else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
4304 {
4305 versionString = "Windows XP";
4306 }
4307 else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
4308 {
4309 versionString = "Windows Server 2003";
4310 }
4311 }
4312 else if( platformID == VER_PLATFORM_WIN32_CE )
4313 {
4314 versionString = "Windows CE";
4315 }
4316
4317exit:
4318 if( inBuffer && ( inBufferSize > 0 ) )
4319 {
4320 inBufferSize -= 1;
4321 strncpy( inBuffer, versionString, inBufferSize );
4322 inBuffer[ inBufferSize ] = '\0';
4323 }
4324 return( err );
4325}
4326
4327
4328//===========================================================================================================================
4329// RegQueryString
4330//===========================================================================================================================
4331
4332mDNSlocal mStatus
4333RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
4334{
4335 DWORD type;
4336 int i;
4337 mStatus err;
4338
4339 *stringLen = MAX_ESCAPED_DOMAIN_NAME;
4340 *string = NULL;
4341 i = 0;
4342
4343 do
4344 {
4345 if ( *string )
4346 {
4347 free( *string );
4348 }
4349
4350 *string = (char*) malloc( *stringLen );
4351 require_action( *string, exit, err = mStatus_NoMemoryErr );
4352
4353 err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
4354
4355 i++;
4356 }
4357 while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
4358
4359 require_noerr_quiet( err, exit );
4360
4361 if ( enabled )
4362 {
4363 DWORD dwSize = sizeof( DWORD );
4364
4365 err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
4366 check_noerr( err );
4367
4368 err = kNoErr;
4369 }
4370
4371exit:
4372
4373 return err;
4374}
4375
4376
4377//===========================================================================================================================
4378// StringToAddress
4379//===========================================================================================================================
4380
4381mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
4382{
4383 struct sockaddr_in6 sa6;
4384 struct sockaddr_in sa4;
4385 INT dwSize;
4386 mStatus err;
4387
4388 sa6.sin6_family = AF_INET6;
4389 dwSize = sizeof( sa6 );
4390
4391 err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
4392
4393 if ( err == mStatus_NoError )
4394 {
4395 err = SetupAddr( ip, (struct sockaddr*) &sa6 );
4396 require_noerr( err, exit );
4397 }
4398 else
4399 {
4400 sa4.sin_family = AF_INET;
4401 dwSize = sizeof( sa4 );
4402
4403 err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
4404 err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
4405 require_noerr( err, exit );
4406
4407 err = SetupAddr( ip, (struct sockaddr*) &sa4 );
4408 require_noerr( err, exit );
4409 }
4410
4411exit:
4412
4413 return err;
4414}
4415
4416
4417//===========================================================================================================================
4418// myGetIfAddrs
4419//===========================================================================================================================
4420
4421mDNSlocal struct ifaddrs*
4422myGetIfAddrs(int refresh)
4423{
4424 static struct ifaddrs *ifa = NULL;
4425
4426 if (refresh && ifa)
4427 {
4428 freeifaddrs(ifa);
4429 ifa = NULL;
4430 }
4431
4432 if (ifa == NULL)
4433 {
4434 getifaddrs(&ifa);
4435 }
4436
4437 return ifa;
4438}
4439
4440
4441//===========================================================================================================================
4442// TCHARtoUTF8
4443//===========================================================================================================================
4444
4445mDNSlocal OSStatus
4446TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
4447{
4448#if( defined( UNICODE ) || defined( _UNICODE ) )
4449 OSStatus err;
4450 int len;
4451
4452 len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
4453 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4454 require_noerr( err, exit );
4455
4456exit:
4457 return( err );
4458#else
4459 return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
4460#endif
4461}
4462
4463
4464//===========================================================================================================================
4465// WindowsLatin1toUTF8
4466//===========================================================================================================================
4467
4468mDNSlocal OSStatus
4469WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
4470{
4471 OSStatus err;
4472 WCHAR * utf16;
4473 int len;
4474
4475 utf16 = NULL;
4476
4477 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4478
4479 len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
4480 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4481 require_noerr( err, exit );
4482
4483 utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
4484 require_action( utf16, exit, err = kNoMemoryErr );
4485
4486 len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
4487 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4488 require_noerr( err, exit );
4489
4490 // Now convert the temporary UTF-16 to UTF-8.
4491
4492 len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
4493 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4494 require_noerr( err, exit );
4495
4496exit:
4497 if( utf16 ) free( utf16 );
4498 return( err );
4499}
4500
4501
4502//===========================================================================================================================
4503// TCPCloseSocket
4504//===========================================================================================================================
4505
4506mDNSlocal void
4507TCPCloseSocket( TCPSocket * sock )
4508{
4509 dlog( kDebugLevelChatty, DEBUG_NAME "closing TCPSocket 0x%x:%d\n", sock, sock->fd );
4510
4511 RemoveFromList( &gTCPDispatchableSockets, sock );
4512
4513 if ( sock->fd != INVALID_SOCKET )
4514 {
4515 closesocket( sock->fd );
4516 sock->fd = INVALID_SOCKET;
4517 }
4518}
4519
4520
4521//===========================================================================================================================
4522// TCPFreeSocket
4523//===========================================================================================================================
4524
4525mDNSlocal void CALLBACK
4526TCPFreeSocket( TCPSocket *sock )
4527{
4528 check( sock );
4529
4530 dlog( kDebugLevelChatty, DEBUG_NAME "freeing TCPSocket 0x%x:%d\n", sock, sock->fd );
4531
4532 if ( sock->connectEvent )
4533 {
4534 CloseHandle( sock->connectEvent );
4535 sock->connectEvent = NULL;
4536 }
4537
4538 if ( sock->fd != INVALID_SOCKET )
4539 {
4540 closesocket( sock->fd );
4541 sock->fd = INVALID_SOCKET;
4542 }
4543
4544 free( sock );
4545}
4546
4547
4548//===========================================================================================================================
4549// UDPCloseSocket
4550//===========================================================================================================================
4551
4552mDNSlocal void
4553UDPCloseSocket( UDPSocket * sock )
4554{
4555 dlog( kDebugLevelChatty, DEBUG_NAME "closing UDPSocket %d\n", sock->fd );
4556
4557 RemoveFromList( &gUDPDispatchableSockets, sock );
4558
4559 if ( sock->fd != INVALID_SOCKET )
4560 {
4561 closesocket( sock->fd );
4562 sock->fd = INVALID_SOCKET;
4563 }
4564}
4565
4566
4567//===========================================================================================================================
4568// UDPFreeSocket
4569//===========================================================================================================================
4570
4571mDNSlocal void CALLBACK
4572UDPFreeSocket( UDPSocket * sock )
4573{
4574 check( sock );
4575
4576 dlog( kDebugLevelChatty, DEBUG_NAME "freeing UDPSocket %d\n", sock->fd );
4577
4578 if ( sock->fd != INVALID_SOCKET )
4579 {
4580 closesocket( sock->fd );
4581 sock->fd = INVALID_SOCKET;
4582 }
4583
4584 free( sock );
4585}
4586
4587//===========================================================================================================================
4588// SetupAddr
4589//===========================================================================================================================
4590
4591mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
4592 {
4593 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
4594
4595 if (sa->sa_family == AF_INET)
4596 {
4597 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
4598 ip->type = mDNSAddrType_IPv4;
4599 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
4600 return(mStatus_NoError);
4601 }
4602
4603 if (sa->sa_family == AF_INET6)
4604 {
4605 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
4606 ip->type = mDNSAddrType_IPv6;
4607 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
4608 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
4609 return(mStatus_NoError);
4610 }
4611
4612 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
4613 return(mStatus_Invalid);
4614 }
4615
4616
4617mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
4618{
4619 LPSTR name = NULL;
4620 DWORD dwSize;
4621 DWORD enabled;
4622 HKEY key = NULL;
4623 OSStatus err;
4624
4625 check( fqdn );
4626
4627 // Initialize
4628
4629 fqdn->c[0] = '\0';
4630
4631 // Get info from Bonjour registry key
4632
4633 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
4634 require_noerr( err, exit );
4635
4636 err = RegQueryString( key, "", &name, &dwSize, &enabled );
4637 if ( !err && ( name[0] != '\0' ) && enabled )
4638 {
4639 if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
4640 {
4641 dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
4642 }
4643 }
4644
4645exit:
4646
4647 if ( key )
4648 {
4649 RegCloseKey( key );
4650 key = NULL;
4651 }
4652
4653 if ( name )
4654 {
4655 free( name );
4656 name = NULL;
4657 }
4658}
4659
4660
4661#ifdef UNICODE
4662mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
4663#else
4664mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
4665#endif
4666{
4667 char subKeyName[kRegistryMaxKeyLength + 1];
4668 DWORD cSubKeys = 0;
4669 DWORD cbMaxSubKey;
4670 DWORD cchMaxClass;
4671 DWORD dwSize;
4672 HKEY key = NULL;
4673 HKEY subKey = NULL;
4674 domainname dname;
4675 DWORD i;
4676 OSStatus err;
4677
4678 check( domains );
4679
4680 // Initialize
4681
4682 *domains = NULL;
4683
4684 err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
4685 require_noerr( err, exit );
4686
4687 // Get information about this node
4688
4689 err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
4690 require_noerr( err, exit );
4691
4692 for ( i = 0; i < cSubKeys; i++)
4693 {
4694 DWORD enabled;
4695
4696 dwSize = kRegistryMaxKeyLength;
4697
4698 err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
4699
4700 if ( !err )
4701 {
4702 err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
4703 require_noerr( err, exit );
4704
4705 dwSize = sizeof( DWORD );
4706 err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
4707
4708 if ( !err && ( subKeyName[0] != '\0' ) && enabled )
4709 {
4710 if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
4711 {
4712 dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
4713 }
4714 else
4715 {
4716 DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
4717 require_action( domain, exit, err = mStatus_NoMemoryErr );
4718
4719 AssignDomainName(&domain->name, &dname);
4720 domain->next = *domains;
4721
4722 *domains = domain;
4723 }
4724 }
4725
4726 RegCloseKey( subKey );
4727 subKey = NULL;
4728 }
4729 }
4730
4731exit:
4732
4733 if ( subKey )
4734 {
4735 RegCloseKey( subKey );
4736 }
4737
4738 if ( key )
4739 {
4740 RegCloseKey( key );
4741 }
4742}
4743
4744
4745mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
4746{
4747 char domainUTF8[ 256 ];
4748 DomainAuthInfo *foundInList;
4749 DomainAuthInfo *ptr;
4750 char outDomain[ 256 ];
4751 char outKey[ 256 ];
4752 char outSecret[ 256 ];
4753 OSStatus err;
4754
4755 ConvertDomainNameToCString( inDomain, domainUTF8 );
4756
4757 // If we're able to find a secret for this domain
4758
4759 if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
4760 {
4761 domainname domain;
4762 domainname key;
4763
4764 // Tell the core about this secret
4765
4766 MakeDomainNameFromDNSNameString( &domain, outDomain );
4767 MakeDomainNameFromDNSNameString( &key, outKey );
4768
4769 for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
4770 if (SameDomainName(&foundInList->domain, &domain ) ) break;
4771
4772 ptr = foundInList;
4773
4774 if (!ptr)
4775 {
4776 ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
4777 require_action( ptr, exit, err = mStatus_NoMemoryErr );
4778 }
4779
4780 err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, NULL, 0, NULL );
4781 require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
4782
4783 debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
4784 }
4785
4786exit:
4787
4788 return;
4789}
4790
4791
4792mDNSlocal VOID CALLBACK
4793CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
4794{
4795 mDNS * const m = ( mDNS * const ) arg;
4796
4797 ( void ) dwTimerLowValue;
4798 ( void ) dwTimerHighValue;
4799
4800 CheckFileShares( m );
4801}
4802
4803
4804mDNSlocal unsigned __stdcall
4805SMBRegistrationThread( void * arg )
4806{
4807 mDNS * const m = ( mDNS * const ) arg;
4808 DNSServiceRef sref = NULL;
4809 HANDLE handles[ 3 ];
4810 mDNSu8 txtBuf[ 256 ];
4811 mDNSu8 * txtPtr;
4812 size_t keyLen;
4813 size_t valLen;
4814 mDNSIPPort port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
4815 DNSServiceErrorType err;
4816
4817 DEBUG_UNUSED( arg );
4818
4819 handles[ 0 ] = gSMBThreadStopEvent;
4820 handles[ 1 ] = gSMBThreadRegisterEvent;
4821 handles[ 2 ] = gSMBThreadDeregisterEvent;
4822
4823 memset( txtBuf, 0, sizeof( txtBuf ) );
4824 txtPtr = txtBuf;
4825 keyLen = strlen( "netbios=" );
4826 valLen = strlen( m->p->nbname );
4827 require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
4828 *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
4829 memcpy( txtPtr, "netbios=", keyLen );
4830 txtPtr += keyLen;
4831 if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
4832 keyLen = strlen( "domain=" );
4833 valLen = strlen( m->p->nbdomain );
4834 require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
4835 *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
4836 memcpy( txtPtr, "domain=", keyLen );
4837 txtPtr += keyLen;
4838 if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
4839
4840 for ( ;; )
4841 {
4842 DWORD ret;
4843
4844 ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
4845
4846 if ( ret != WAIT_FAILED )
4847 {
4848 if ( ret == kSMBStopEvent )
4849 {
4850 break;
4851 }
4852 else if ( ret == kSMBRegisterEvent )
4853 {
4854 err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
4855
4856 if ( err )
4857 {
4858 LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
4859 sref = NULL;
4860 break;
4861 }
4862 }
4863 else if ( ret == kSMBDeregisterEvent )
4864 {
4865 if ( sref )
4866 {
4867 gDNSServiceRefDeallocate( sref );
4868 sref = NULL;
4869 }
4870 }
4871 }
4872 else
4873 {
4874 LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
4875 break;
4876 }
4877 }
4878
4879exit:
4880
4881 if ( sref != NULL )
4882 {
4883 gDNSServiceRefDeallocate( sref );
4884 sref = NULL;
4885 }
4886
4887 SetEvent( gSMBThreadQuitEvent );
4888 _endthreadex( 0 );
4889 return 0;
4890}
4891
4892
4893mDNSlocal void
4894CheckFileShares( mDNS * const m )
4895{
4896 PSHARE_INFO_1 bufPtr = ( PSHARE_INFO_1 ) NULL;
4897 DWORD entriesRead = 0;
4898 DWORD totalEntries = 0;
4899 DWORD resume = 0;
4900 mDNSBool advertise = mDNSfalse;
4901 mDNSBool fileSharing = mDNSfalse;
4902 mDNSBool printSharing = mDNSfalse;
4903 HKEY key = NULL;
4904 BOOL retry = FALSE;
4905 NET_API_STATUS res;
4906 mStatus err;
4907
4908 check( m );
4909
4910 // Only do this if we're not shutting down
4911
4912 require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
4913
4914 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
4915
4916 if ( !err )
4917 {
4918 DWORD dwSize = sizeof( DWORD );
4919 RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
4920 }
4921
4922 if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
4923 {
4924 dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
4925
4926 res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
4927
4928 if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
4929 {
4930 PSHARE_INFO_1 p = bufPtr;
4931 DWORD i;
4932
4933 for( i = 0; i < entriesRead; i++ )
4934 {
4935 // We are only interested if the user is sharing anything other
4936 // than the built-in "print$" source
4937
4938 if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
4939 {
4940 fileSharing = mDNStrue;
4941 }
4942 else if ( p->shi1_type == STYPE_PRINTQ )
4943 {
4944 printSharing = mDNStrue;
4945 }
4946
4947 p++;
4948 }
4949
4950 NetApiBufferFree( bufPtr );
4951 bufPtr = NULL;
4952 retry = FALSE;
4953 }
4954 else if ( res == NERR_ServerNotStarted )
4955 {
4956 retry = TRUE;
4957 }
4958 }
4959
4960 if ( retry )
4961 {
4962 __int64 qwTimeout;
4963 LARGE_INTEGER liTimeout;
4964
4965 qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
4966 liTimeout.LowPart = ( DWORD )( qwTimeout & 0xFFFFFFFF );
4967 liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
4968
4969 SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
4970 }
4971
4972 if ( !m->p->smbFileSharing && fileSharing )
4973 {
4974 if ( !gSMBThread )
4975 {
4976 if ( !gDNSSDLibrary )
4977 {
4978 gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
4979 require_action( gDNSSDLibrary, exit, err = GetLastError() );
4980 }
4981
4982 if ( !gDNSServiceRegister )
4983 {
4984 gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
4985 require_action( gDNSServiceRegister, exit, err = GetLastError() );
4986 }
4987
4988 if ( !gDNSServiceRefDeallocate )
4989 {
4990 gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
4991 require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
4992 }
4993
4994 if ( !gSMBThreadRegisterEvent )
4995 {
4996 gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
4997 require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
4998 }
4999
5000 if ( !gSMBThreadDeregisterEvent )
5001 {
5002 gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5003 require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
5004 }
5005
5006 if ( !gSMBThreadStopEvent )
5007 {
5008 gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5009 require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
5010 }
5011
5012 if ( !gSMBThreadQuitEvent )
5013 {
5014 gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5015 require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
5016 }
5017
5018 gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
5019 require_action( gSMBThread != NULL, exit, err = GetLastError() );
5020 }
5021
5022 SetEvent( gSMBThreadRegisterEvent );
5023
5024 m->p->smbFileSharing = mDNStrue;
5025 }
5026 else if ( m->p->smbFileSharing && !fileSharing )
5027 {
5028 dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
5029
5030 if ( gSMBThreadDeregisterEvent != NULL )
5031 {
5032 SetEvent( gSMBThreadDeregisterEvent );
5033 }
5034
5035 m->p->smbFileSharing = mDNSfalse;
5036 }
5037
5038exit:
5039
5040 if ( key )
5041 {
5042 RegCloseKey( key );
5043 }
5044}
5045
5046
5047BOOL
5048IsWOMPEnabled( mDNS * const m )
5049{
5050 BOOL enabled;
5051
5052 mDNSInterfaceData * ifd;
5053
5054 enabled = FALSE;
5055
5056 for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
5057 {
5058 if ( IsWOMPEnabledForAdapter( ifd->name ) )
5059 {
5060 enabled = TRUE;
5061 break;
5062 }
5063 }
5064
5065 return enabled;
5066}
5067
5068
5069mDNSlocal mDNSu8
5070IsWOMPEnabledForAdapter( const char * adapterName )
5071{
5072 char fileName[80];
5073 NDIS_OID oid;
5074 DWORD count;
5075 HANDLE handle = INVALID_HANDLE_VALUE;
5076 NDIS_PNP_CAPABILITIES * pNPC = NULL;
5077 int err;
5078 mDNSu8 ok = TRUE;
5079
5080 require_action( adapterName != NULL, exit, ok = FALSE );
5081
5082 dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
5083
5084 // Construct a device name to pass to CreateFile
5085
5086 strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
5087 strcat_s( fileName, sizeof( fileName ), adapterName );
5088 handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
5089 require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
5090
5091 // We successfully opened the driver, format the IOCTL to pass the driver.
5092
5093 oid = OID_PNP_CAPABILITIES;
5094 pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
5095 require_action( pNPC != NULL, exit, ok = FALSE );
5096 ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
5097 err = translate_errno( ok, GetLastError(), kUnknownErr );
5098 require_action( !err, exit, ok = FALSE );
5099 ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
5100
5101exit:
5102
5103 if ( pNPC != NULL )
5104 {
5105 free( pNPC );
5106 }
5107
5108 if ( handle != INVALID_HANDLE_VALUE )
5109 {
5110 CloseHandle( handle );
5111 }
5112
5113 dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
5114
5115 return ( mDNSu8 ) ok;
5116}
5117
5118
5119void
5120DispatchSocketEvents( mDNS * const inMDNS )
5121{
5122 UDPSocket * udpSock;
5123 TCPSocket * tcpSock;
5124
5125 while ( ( udpSock = ( UDPSocket* ) gUDPDispatchableSockets.Head ) != NULL )
5126 {
5127 dlog( kDebugLevelChatty, DEBUG_NAME "%s: calling DispatchUDPEvent on socket %d, error = %d, bytesTransferred = %d\n",
5128 __ROUTINE__, udpSock->fd, udpSock->overlapped.error, udpSock->overlapped.bytesTransferred );
5129 RemoveFromList( &gUDPDispatchableSockets, udpSock );
5130 DispatchUDPEvent( inMDNS, udpSock );
5131 }
5132
5133 while ( ( tcpSock = ( TCPSocket* ) gTCPDispatchableSockets.Head ) != NULL )
5134 {
5135 dlog( kDebugLevelChatty, DEBUG_NAME "%s: calling DispatchTCPEvent on socket %d, error = %d, bytesTransferred = %d\n",
5136 __ROUTINE__, tcpSock->fd, tcpSock->overlapped.error, tcpSock->overlapped.bytesTransferred );
5137 RemoveFromList( &gTCPDispatchableSockets, tcpSock );
5138 DispatchTCPEvent( inMDNS, tcpSock );
5139 }
5140}
5141
5142
5143mDNSlocal void
5144DispatchUDPEvent( mDNS * const inMDNS, UDPSocket * sock )
5145{
5146 ( void ) inMDNS;
5147
5148 // If we've closed the socket, then we want to ignore
5149 // this read. The packet might have been queued before
5150 // the socket was closed.
5151
5152 if ( sock->fd != INVALID_SOCKET )
5153 {
5154 const mDNSInterfaceID iid = sock->ifd ? sock->ifd->interfaceInfo.InterfaceID : NULL;
5155 mDNSu8 * end = ( (mDNSu8 *) &sock->packet ) + sock->overlapped.bytesTransferred;
5156
5157 dlog( kDebugLevelChatty, DEBUG_NAME "calling mDNSCoreReceive on socket: %d\n", sock->fd );
5158 mDNSCoreReceive( sock->m, &sock->packet, end, &sock->overlapped.srcAddr, sock->overlapped.srcPort, &sock->overlapped.dstAddr, sock->overlapped.dstPort, iid );
5159 }
5160
5161 // If the socket is still good, then start up another asynchronous read
5162
5163 if ( sock->fd != INVALID_SOCKET )
5164 {
5165 int err = UDPBeginRecv( sock );
5166 check_noerr( err );
5167 }
5168}
5169
5170
5171mDNSlocal void
5172DispatchTCPEvent( mDNS * const inMDNS, TCPSocket * sock )
5173{
5174 ( void ) inMDNS;
5175
5176 if ( sock->fd != INVALID_SOCKET )
5177 {
5178 sock->eptr += sock->overlapped.bytesTransferred;
5179 sock->lastError = sock->overlapped.error;
5180
5181 if ( !sock->overlapped.error && !sock->overlapped.bytesTransferred )
5182 {
5183 sock->closed = TRUE;
5184 }
5185
5186 if ( sock->readEventHandler != NULL )
5187 {
5188 dlog( kDebugLevelChatty, DEBUG_NAME "calling TCP read handler on socket: %d\n", sock->fd );
5189 sock->readEventHandler( sock );
5190 }
5191 }
5192
5193 // If the socket is still good, then start up another asynchronous read
5194
5195 if ( !sock->closed && ( sock->fd != INVALID_SOCKET ) )
5196 {
5197 int err = TCPBeginRecv( sock );
5198 check_noerr( err );
5199 }
5200}