1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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).
33 #include "CommonServices.h"
34 #include "DebugServices.h"
46 #include <ntddndis.h> // This defines the IOCTL constants.
48 #include "mDNSEmbeddedAPI.h"
49 #include "GenLinkedList.h"
50 #include "DNSCommon.h"
51 #include "mDNSWin32.h"
54 #pragma mark == Constants ==
57 //===========================================================================================================================
59 //===========================================================================================================================
61 #define DEBUG_NAME "[mDNSWin32] "
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
69 #define kMDNSDefaultName "My Computer"
71 #define kWinSockMajorMin 2
72 #define kWinSockMinorMin 2
74 #define kRegistryMaxKeyLength 255
75 #define kRegistryMaxValueName 16383
77 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
79 #define kIPv6IfIndexBase (10000000L)
80 #define SMBPortAsNumber 445
81 #define DEVICE_PREFIX "\\\\.\\"
84 #pragma mark == Prototypes ==
87 //===========================================================================================================================
89 //===========================================================================================================================
91 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
92 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
93 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
94 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
95 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
96 mDNSlocal
void CALLBACK
FreeInterface( mDNSInterfaceData
*inIFD
);
97 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
98 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
99 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
);
100 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
);
101 mDNSlocal
void freeifaddrs( struct ifaddrs
*inAddrs
);
105 // Platform Accessors
111 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
112 struct mDNSPlatformInterfaceInfo
119 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
120 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
124 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
125 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
128 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
131 mDNSlocal DWORD
GetPrimaryInterface();
132 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
133 mDNSlocal mDNSBool
CanReceiveUnicast( void );
134 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
136 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
137 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
138 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
139 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
140 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
141 mDNSlocal
void TCPDidConnect( mDNS
* const inMDNS
, HANDLE event
, void * context
);
142 mDNSlocal
void TCPCanRead( TCPSocket
* sock
);
143 mDNSlocal mStatus
TCPBeginRecv( TCPSocket
* sock
);
144 mDNSlocal
void CALLBACK
TCPEndRecv( DWORD error
, DWORD bytesTransferred
, LPWSAOVERLAPPED overlapped
, DWORD flags
);
145 mDNSlocal
void CALLBACK
TCPFreeSocket( TCPSocket
*sock
);
146 mDNSlocal OSStatus
UDPBeginRecv( UDPSocket
* socket
);
147 mDNSlocal
void CALLBACK
UDPEndRecv( DWORD err
, DWORD bytesTransferred
, LPWSAOVERLAPPED overlapped
, DWORD flags
);
148 mDNSlocal
void CALLBACK
UDPFreeSocket( UDPSocket
* sock
);
149 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
);
150 mDNSlocal
void GetDDNSFQDN( domainname
*const fqdn
);
152 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCWSTR lpSubKey
);
154 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCSTR lpSubKey
);
156 mDNSlocal
void SetDomainSecrets( mDNS
* const inMDNS
);
157 mDNSlocal
void SetDomainSecret( mDNS
* const m
, const domainname
* inDomain
);
158 mDNSlocal VOID CALLBACK
CheckFileSharesProc( LPVOID arg
, DWORD dwTimerLowValue
, DWORD dwTimerHighValue
);
159 mDNSlocal
void CheckFileShares( mDNS
* const inMDNS
);
160 mDNSlocal
void SMBCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
161 mDNSlocal mDNSu8
IsWOMPEnabledForAdapter( const char * adapterName
);
162 mDNSlocal
void FreeSocketEventsForSocket( mDNS
* const inMDNS
, void * sock
);
163 mDNSlocal
void FreeSocketEvents( mDNS
* const inMDNS
);
164 mDNSlocal
void TCPSocketEventHandler( mDNS
* const inMDNS
, void * v
);
165 mDNSlocal
void UDPSocketEventHandler( mDNS
* const inMDNS
, void * v
);
172 #pragma mark == Globals ==
175 //===========================================================================================================================
177 //===========================================================================================================================
179 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
180 mDNSs32 mDNSPlatformOneSecond
= 0;
181 mDNSlocal UDPSocket
* gUDPSocketList
= NULL
;
182 mDNSlocal
int gUDPSockets
= 0;
183 mDNSlocal BOOL gSocketEventsEnabled
= FALSE
;
184 mDNSlocal GenLinkedList gSocketEvents
;
186 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
189 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
193 PIP_ADAPTER_ADDRESSES inAdapter
,
194 PULONG outBufferSize
);
196 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
197 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
203 typedef ULONG_PTR HCRYPTPROV
; // WinCrypt.h, line 249
207 #ifndef CRYPT_MACHINE_KEYSET
208 # define CRYPT_MACHINE_KEYSET 0x00000020
211 #ifndef CRYPT_NEWKEYSET
212 # define CRYPT_NEWKEYSET 0x00000008
215 #ifndef PROV_RSA_FULL
216 # define PROV_RSA_FULL 1
219 typedef BOOL (__stdcall
*fnCryptGenRandom
)( HCRYPTPROV
, DWORD
, BYTE
* );
220 typedef BOOL (__stdcall
*fnCryptAcquireContext
)( HCRYPTPROV
*, LPCTSTR
, LPCTSTR
, DWORD
, DWORD
);
221 typedef BOOL (__stdcall
*fnCryptReleaseContext
)(HCRYPTPROV
, DWORD
);
223 static fnCryptAcquireContext g_lpCryptAcquireContext
= NULL
;
224 static fnCryptReleaseContext g_lpCryptReleaseContext
= NULL
;
225 static fnCryptGenRandom g_lpCryptGenRandom
= NULL
;
226 static HINSTANCE g_hAAPI32
= NULL
;
227 static HCRYPTPROV g_hProvider
= ( ULONG_PTR
) NULL
;
230 typedef DNSServiceErrorType ( DNSSD_API
*DNSServiceRegisterFunc
)
232 DNSServiceRef
*sdRef
,
233 DNSServiceFlags flags
,
234 uint32_t interfaceIndex
,
235 const char *name
, /* may be NULL */
237 const char *domain
, /* may be NULL */
238 const char *host
, /* may be NULL */
241 const void *txtRecord
, /* may be NULL */
242 DNSServiceRegisterReply callBack
, /* may be NULL */
243 void *context
/* may be NULL */
247 typedef void ( DNSSD_API
*DNSServiceRefDeallocateFunc
)( DNSServiceRef sdRef
);
249 mDNSlocal HMODULE gDNSSDLibrary
= NULL
;
250 mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister
= NULL
;
251 mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate
= NULL
;
252 mDNSlocal HANDLE gSMBThread
= NULL
;
253 mDNSlocal HANDLE gSMBThreadRegisterEvent
= NULL
;
254 mDNSlocal HANDLE gSMBThreadDeregisterEvent
= NULL
;
255 mDNSlocal HANDLE gSMBThreadStopEvent
= NULL
;
256 mDNSlocal HANDLE gSMBThreadQuitEvent
= NULL
;
258 #define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
259 #define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
260 #define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
265 #pragma mark == Platform Support ==
268 //===========================================================================================================================
270 //===========================================================================================================================
272 mDNSexport mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
277 struct sockaddr_in sa4
;
278 struct sockaddr_in6 sa6
;
284 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
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.
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( &gSocketEvents
, offsetof( SocketEvent
, next
));
299 // Startup WinSock 2.2 or later.
301 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
302 require_noerr( err
, exit
);
304 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
305 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
307 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
309 // Setup the HINFO HW strings.
310 //<rdar://problem/7245119> device-info should have model=Windows
312 strcpy_s( ( char* ) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2, "Windows" );
313 inMDNS
->HIHardware
.c
[ 0 ] = ( mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
314 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
316 // Setup the HINFO SW strings.
317 #if ( MDNS_SET_HINFO_STRINGS )
318 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
319 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
320 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
321 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
324 // Set the thread global overlapped flag
327 err
= setsockopt( INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, ( char* ) &val
, sizeof( val
) );
328 err
= translate_errno( err
!= SOCKET_ERROR
, WSAGetLastError(), kUnknownErr
);
329 require_noerr( err
, exit
);
331 // Set up the IPv4 unicast socket
333 inMDNS
->p
->unicastSock4
.fd
= INVALID_SOCKET
;
334 inMDNS
->p
->unicastSock4
.recvMsgPtr
= NULL
;
335 inMDNS
->p
->unicastSock4
.ifd
= NULL
;
336 inMDNS
->p
->unicastSock4
.next
= NULL
;
337 inMDNS
->p
->unicastSock4
.m
= inMDNS
;
339 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
341 sa4
.sin_family
= AF_INET
;
342 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
343 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
.fd
);
345 sa4len
= sizeof( sa4
);
346 err
= getsockname( inMDNS
->p
->unicastSock4
.fd
, (struct sockaddr
*) &sa4
, &sa4len
);
347 require_noerr( err
, exit
);
348 inMDNS
->p
->unicastSock4
.port
.NotAnInteger
= sa4
.sin_port
;
349 inMDNS
->UnicastPort4
= inMDNS
->p
->unicastSock4
.port
;
350 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
);
354 inMDNS
->p
->unicastSock4
.recvMsgPtr
= NULL
;
357 err
= UDPBeginRecv( &inMDNS
->p
->unicastSock4
);
358 require_noerr( err
, exit
);
362 // Set up the IPv6 unicast socket
364 inMDNS
->p
->unicastSock6
.fd
= INVALID_SOCKET
;
365 inMDNS
->p
->unicastSock6
.recvMsgPtr
= NULL
;
366 inMDNS
->p
->unicastSock6
.ifd
= NULL
;
367 inMDNS
->p
->unicastSock6
.next
= NULL
;
368 inMDNS
->p
->unicastSock6
.m
= inMDNS
;
370 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
372 sa6
.sin6_family
= AF_INET6
;
373 sa6
.sin6_addr
= in6addr_any
;
374 sa6
.sin6_scope_id
= 0;
376 // This call will fail if the machine hasn't installed IPv6. In that case,
377 // the error will be WSAEAFNOSUPPORT.
379 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
.fd
);
380 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
383 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
385 if ( inMDNS
->p
->unicastSock6
.fd
!= INVALID_SOCKET
)
387 sa6len
= sizeof( sa6
);
388 err
= getsockname( inMDNS
->p
->unicastSock6
.fd
, (struct sockaddr
*) &sa6
, &sa6len
);
389 require_noerr( err
, exit
);
390 inMDNS
->p
->unicastSock6
.port
.NotAnInteger
= sa6
.sin6_port
;
391 inMDNS
->UnicastPort6
= inMDNS
->p
->unicastSock6
.port
;
393 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 inMDNS
->p
->unicastSock6
.recvMsgPtr
= NULL
;
400 err
= UDPBeginRecv( &inMDNS
->p
->unicastSock6
);
401 require_noerr( err
, exit
);
406 // Notify core of domain secret keys
408 SetDomainSecrets( inMDNS
);
412 mDNSCoreInitComplete( inMDNS
, err
);
419 mDNSPlatformClose( inMDNS
);
422 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
426 //===========================================================================================================================
428 //===========================================================================================================================
430 mDNSexport
void mDNSPlatformClose( mDNS
* const inMDNS
)
434 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
437 if ( gSMBThread
!= NULL
)
439 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down smb registration thread\n" );
440 SetEvent( gSMBThreadStopEvent
);
442 if ( WaitForSingleObject( gSMBThreadQuitEvent
, 5 * 1000 ) == WAIT_OBJECT_0
)
444 if ( gSMBThreadQuitEvent
)
446 CloseHandle( gSMBThreadQuitEvent
);
447 gSMBThreadQuitEvent
= NULL
;
450 if ( gSMBThreadStopEvent
)
452 CloseHandle( gSMBThreadStopEvent
);
453 gSMBThreadStopEvent
= NULL
;
456 if ( gSMBThreadDeregisterEvent
)
458 CloseHandle( gSMBThreadDeregisterEvent
);
459 gSMBThreadDeregisterEvent
= NULL
;
462 if ( gSMBThreadRegisterEvent
)
464 CloseHandle( gSMBThreadRegisterEvent
);
465 gSMBThreadRegisterEvent
= NULL
;
470 FreeLibrary( gDNSSDLibrary
);
471 gDNSSDLibrary
= NULL
;
476 LogMsg( "Unable to stop SMBThread" );
479 inMDNS
->p
->smbFileSharing
= mDNSfalse
;
480 inMDNS
->p
->smbPrintSharing
= mDNSfalse
;
483 // Tear everything down in reverse order to how it was set up.
485 err
= TearDownInterfaceList( inMDNS
);
487 check( !inMDNS
->p
->inactiveInterfaceList
);
489 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
491 if ( inMDNS
->p
->unicastSock4
.fd
!= INVALID_SOCKET
)
493 closesocket( inMDNS
->p
->unicastSock4
.fd
);
494 inMDNS
->p
->unicastSock4
.fd
= INVALID_SOCKET
;
499 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
501 if ( inMDNS
->p
->unicastSock6
.fd
!= INVALID_SOCKET
)
503 closesocket( inMDNS
->p
->unicastSock6
.fd
);
504 inMDNS
->p
->unicastSock6
.fd
= INVALID_SOCKET
;
509 // Free the DLL needed for IPv6 support.
511 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
512 if( gIPHelperLibraryInstance
)
514 gGetAdaptersAddressesFunctionPtr
= NULL
;
516 FreeLibrary( gIPHelperLibraryInstance
);
517 gIPHelperLibraryInstance
= NULL
;
523 // Release any resources
525 if ( g_hProvider
&& g_lpCryptReleaseContext
)
527 ( g_lpCryptReleaseContext
)( g_hProvider
, 0 );
530 // Free the AdvApi32.dll
532 FreeLibrary( g_hAAPI32
);
534 // And reset all the data
536 g_lpCryptAcquireContext
= NULL
;
537 g_lpCryptReleaseContext
= NULL
;
538 g_lpCryptGenRandom
= NULL
;
539 g_hProvider
= ( ULONG_PTR
) NULL
;
543 // Clear out the APC queue
545 SetSocketEventsEnabled( inMDNS
, TRUE
);
546 while ( SleepEx( 0, TRUE
) == WAIT_IO_COMPLETION
);
547 SetSocketEventsEnabled( inMDNS
, FALSE
);
551 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
555 //===========================================================================================================================
557 //===========================================================================================================================
559 mDNSexport
void mDNSPlatformLock( const mDNS
* const inMDNS
)
564 //===========================================================================================================================
565 // mDNSPlatformUnlock
566 //===========================================================================================================================
568 mDNSexport
void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
573 //===========================================================================================================================
574 // mDNSPlatformStrCopy
575 //===========================================================================================================================
577 mDNSexport
void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
582 strcpy( (char *) inDst
, (const char*) inSrc
);
585 //===========================================================================================================================
586 // mDNSPlatformStrLen
587 //===========================================================================================================================
589 mDNSexport mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
593 return( (mDNSu32
) strlen( (const char *) inSrc
) );
596 //===========================================================================================================================
597 // mDNSPlatformMemCopy
598 //===========================================================================================================================
600 mDNSexport
void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
605 memcpy( inDst
, inSrc
, inSize
);
608 //===========================================================================================================================
609 // mDNSPlatformMemSame
610 //===========================================================================================================================
612 mDNSexport mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
617 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
620 //===========================================================================================================================
621 // mDNSPlatformMemZero
622 //===========================================================================================================================
624 mDNSexport
void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
628 memset( inDst
, 0, inSize
);
631 //===========================================================================================================================
632 // mDNSPlatformMemAllocate
633 //===========================================================================================================================
635 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
641 mem
= malloc( inSize
);
647 //===========================================================================================================================
648 // mDNSPlatformMemFree
649 //===========================================================================================================================
651 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
658 //===========================================================================================================================
659 // mDNSPlatformRandomNumber
660 //===========================================================================================================================
662 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
664 mDNSu32 randomNumber
= 0;
670 g_hAAPI32
= LoadLibrary( TEXT("AdvAPI32.dll") );
671 err
= translate_errno( g_hAAPI32
!= NULL
, GetLastError(), mStatus_UnknownErr
);
672 require_noerr( err
, exit
);
675 // Function Pointer: CryptAcquireContext
677 if ( !g_lpCryptAcquireContext
)
679 g_lpCryptAcquireContext
= ( fnCryptAcquireContext
)
681 ( GetProcAddress( g_hAAPI32
, "CryptAcquireContextW" ) );
683 ( GetProcAddress( g_hAAPI32
, "CryptAcquireContextA" ) );
685 err
= translate_errno( g_lpCryptAcquireContext
!= NULL
, GetLastError(), mStatus_UnknownErr
);
686 require_noerr( err
, exit
);
689 // Function Pointer: CryptReleaseContext
691 if ( !g_lpCryptReleaseContext
)
693 g_lpCryptReleaseContext
= ( fnCryptReleaseContext
)
694 ( GetProcAddress( g_hAAPI32
, "CryptReleaseContext" ) );
695 err
= translate_errno( g_lpCryptReleaseContext
!= NULL
, GetLastError(), mStatus_UnknownErr
);
696 require_noerr( err
, exit
);
699 // Function Pointer: CryptGenRandom
701 if ( !g_lpCryptGenRandom
)
703 g_lpCryptGenRandom
= ( fnCryptGenRandom
)
704 ( GetProcAddress( g_hAAPI32
, "CryptGenRandom" ) );
705 err
= translate_errno( g_lpCryptGenRandom
!= NULL
, GetLastError(), mStatus_UnknownErr
);
706 require_noerr( err
, exit
);
713 bResult
= (*g_lpCryptAcquireContext
)( &g_hProvider
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
);
717 bResult
= ( *g_lpCryptAcquireContext
)( &g_hProvider
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
| CRYPT_NEWKEYSET
);
718 err
= translate_errno( bResult
, GetLastError(), mStatus_UnknownErr
);
719 require_noerr( err
, exit
);
723 bResult
= (*g_lpCryptGenRandom
)( g_hProvider
, sizeof( randomNumber
), ( BYTE
* ) &randomNumber
);
724 err
= translate_errno( bResult
, GetLastError(), mStatus_UnknownErr
);
725 require_noerr( err
, exit
);
731 randomNumber
= rand();
737 //===========================================================================================================================
738 // mDNSPlatformTimeInit
739 //===========================================================================================================================
741 mDNSexport mStatus
mDNSPlatformTimeInit( void )
743 // No special setup is required on Windows -- we just use GetTickCount().
744 return( mStatus_NoError
);
747 //===========================================================================================================================
748 // mDNSPlatformRawTime
749 //===========================================================================================================================
751 mDNSexport mDNSs32
mDNSPlatformRawTime( void )
753 return( (mDNSs32
) GetTickCount() );
756 //===========================================================================================================================
758 //===========================================================================================================================
760 mDNSexport mDNSs32
mDNSPlatformUTC( void )
762 return ( mDNSs32
) time( NULL
);
765 //===========================================================================================================================
766 // mDNSPlatformInterfaceNameToID
767 //===========================================================================================================================
769 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
772 mDNSInterfaceData
* ifd
;
778 // Search for an interface with the specified name,
780 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
782 if( strcmp( ifd
->name
, inName
) == 0 )
787 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
793 *outID
= (mDNSInterfaceID
) ifd
;
795 err
= mStatus_NoError
;
801 //===========================================================================================================================
802 // mDNSPlatformInterfaceIDToInfo
803 //===========================================================================================================================
805 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
808 mDNSInterfaceData
* ifd
;
814 // Search for an interface with the specified ID,
816 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
818 if( ifd
== (mDNSInterfaceData
*) inID
)
823 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
827 outInfo
->name
= ifd
->name
;
828 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
829 err
= mStatus_NoError
;
835 //===========================================================================================================================
836 // mDNSPlatformInterfaceIDfromInterfaceIndex
837 //===========================================================================================================================
839 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
* const inMDNS
, mDNSu32 inIndex
)
844 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
846 id
= mDNSInterface_LocalOnly
;
848 /* uncomment if Windows ever supports P2P
849 else if( inIndex == kDNSServiceInterfaceIndexP2P )
851 id = mDNSInterface_P2P;
854 else if( inIndex
!= 0 )
856 mDNSInterfaceData
* ifd
;
858 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
860 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
862 id
= ifd
->interfaceInfo
.InterfaceID
;
871 //===========================================================================================================================
872 // mDNSPlatformInterfaceIndexfromInterfaceID
873 //===========================================================================================================================
875 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
* const inMDNS
, mDNSInterfaceID inID
)
880 if( inID
== mDNSInterface_LocalOnly
)
882 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
884 /* uncomment if Windows ever supports P2P
885 else if( inID == mDNSInterface_P2P )
887 index = (mDNSu32) kDNSServiceInterfaceIndexP2P;
892 mDNSInterfaceData
* ifd
;
894 // Search active interfaces.
895 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
897 if( (mDNSInterfaceID
) ifd
== inID
)
899 index
= ifd
->scopeID
;
904 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
908 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
910 if( (mDNSInterfaceID
) ifd
== inID
)
912 index
= ifd
->scopeID
;
923 //===========================================================================================================================
924 // mDNSPlatformTCPSocket
925 //===========================================================================================================================
928 mDNSPlatformTCPSocket
931 TCPSocketFlags flags
,
935 TCPSocket
* sock
= NULL
;
936 u_long on
= 1; // "on" for setsockopt
937 struct sockaddr_in saddr
;
939 mStatus err
= mStatus_NoError
;
943 require_action( flags
== 0, exit
, err
= mStatus_UnsupportedErr
);
945 // Setup connection data object
947 sock
= (TCPSocket
*) malloc( sizeof( TCPSocket
) );
948 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
949 mDNSPlatformMemZero( sock
, sizeof( TCPSocket
) );
950 sock
->fd
= INVALID_SOCKET
;
954 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
955 saddr
.sin_family
= AF_INET
;
956 saddr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
957 saddr
.sin_port
= port
->NotAnInteger
;
961 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
962 err
= translate_errno( sock
->fd
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
963 require_noerr( err
, exit
);
967 err
= bind( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
968 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
969 require_noerr( err
, exit
);
971 // Set it to be non-blocking
973 err
= ioctlsocket( sock
->fd
, FIONBIO
, &on
);
974 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
975 require_noerr( err
, exit
);
979 mDNSPlatformMemZero( &saddr
, sizeof( saddr
) );
980 len
= sizeof( saddr
);
982 err
= getsockname( sock
->fd
, ( struct sockaddr
* ) &saddr
, &len
);
983 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
984 require_noerr( err
, exit
);
986 port
->NotAnInteger
= saddr
.sin_port
;
992 TCPFreeSocket( sock
);
999 //===========================================================================================================================
1000 // mDNSPlatformTCPConnect
1001 //===========================================================================================================================
1004 mDNSPlatformTCPConnect
1007 const mDNSAddr
* inDstIP
,
1008 mDNSOpaque16 inDstPort
,
1009 domainname
* hostname
,
1010 mDNSInterfaceID inInterfaceID
,
1011 TCPConnectionCallback inCallback
,
1015 struct sockaddr_in saddr
;
1017 mStatus err
= mStatus_NoError
;
1019 DEBUG_UNUSED( inInterfaceID
);
1021 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1023 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1024 return mStatus_UnknownErr
;
1027 // Setup connection data object
1029 sock
->readEventHandler
= TCPCanRead
;
1030 sock
->userCallback
= inCallback
;
1031 sock
->userContext
= inContext
;
1033 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1034 saddr
.sin_family
= AF_INET
;
1035 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1036 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1038 // Try and do connect
1040 err
= connect( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1041 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1042 sock
->connected
= !err
? TRUE
: FALSE
;
1044 if ( sock
->connected
)
1046 err
= TCPAddSocket( sock
->m
, sock
);
1047 require_noerr( err
, exit
);
1051 require_action( sock
->m
->p
->registerWaitableEventFunc
!= NULL
, exit
, err
= mStatus_ConnFailed
);
1053 sock
->connectEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1054 err
= translate_errno( sock
->connectEvent
, GetLastError(), mStatus_UnknownErr
);
1055 require_noerr( err
, exit
);
1057 err
= WSAEventSelect( sock
->fd
, sock
->connectEvent
, FD_CONNECT
);
1058 require_noerr( err
, exit
);
1060 err
= sock
->m
->p
->registerWaitableEventFunc( sock
->m
, sock
->connectEvent
, sock
, TCPDidConnect
);
1061 require_noerr( err
, exit
);
1068 err
= sock
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1074 //===========================================================================================================================
1075 // mDNSPlatformTCPAccept
1076 //===========================================================================================================================
1079 mDNSexport TCPSocket
*mDNSPlatformTCPAccept( TCPSocketFlags flags
, int fd
)
1081 TCPSocket
* sock
= NULL
;
1082 mStatus err
= mStatus_NoError
;
1084 require_action( !flags
, exit
, err
= mStatus_UnsupportedErr
);
1086 sock
= malloc( sizeof( TCPSocket
) );
1087 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1089 mDNSPlatformMemZero( sock
, sizeof( *sock
) );
1092 sock
->flags
= flags
;
1106 //===========================================================================================================================
1107 // mDNSPlatformTCPCloseConnection
1108 //===========================================================================================================================
1110 mDNSexport
void mDNSPlatformTCPCloseConnection( TCPSocket
*sock
)
1114 if ( sock
->connectEvent
&& sock
->m
->p
->unregisterWaitableEventFunc
)
1116 sock
->m
->p
->unregisterWaitableEventFunc( sock
->m
, sock
->connectEvent
);
1119 if ( sock
->fd
!= INVALID_SOCKET
)
1121 closesocket( sock
->fd
);
1122 sock
->fd
= INVALID_SOCKET
;
1124 QueueUserAPC( ( PAPCFUNC
) TCPFreeSocket
, sock
->m
->p
->mainThread
, ( ULONG_PTR
) sock
);
1127 FreeSocketEventsForSocket( sock
->m
, sock
);
1130 //===========================================================================================================================
1131 // mDNSPlatformReadTCP
1132 //===========================================================================================================================
1134 mDNSexport
long mDNSPlatformReadTCP( TCPSocket
*sock
, void *inBuffer
, unsigned long inBufferSize
, mDNSBool
* closed
)
1136 unsigned long bytesLeft
;
1140 *closed
= sock
->closed
;
1141 wsaError
= sock
->lastError
;
1148 else if ( sock
->lastError
== 0 )
1150 // First check to see if we have any data left in our buffer
1152 bytesLeft
= ( DWORD
) ( sock
->eptr
- sock
->bptr
);
1156 unsigned long bytesToCopy
= ( bytesLeft
< inBufferSize
) ? bytesLeft
: inBufferSize
;
1158 memcpy( inBuffer
, sock
->bptr
, bytesToCopy
);
1159 sock
->bptr
+= bytesToCopy
;
1163 if ( bytesLeft
== bytesToCopy
)
1165 sock
->lastError
= TCPBeginRecv( sock
);
1167 // If we can't immediately queue up another read, abort the connection
1168 // now, even if we successfully wrote bytes to the buffer.
1169 // We don't expect this to happen unless something is seriously borked.
1170 // If we run into this in the real world, we should consider queuing up
1171 // a user APC function to defer an explicit callback to the read event handler
1172 // to inform the consumer of the problem.
1174 if ( sock
->lastError
)
1176 dlog( kDebugLevelError
, DEBUG_NAME
"TCPBeginRecv failed with error %d\n", sock
->lastError
);
1177 wsaError
= sock
->lastError
;
1184 wsaError
= WSAEWOULDBLOCK
;
1188 // Always set the last winsock error, so that we don't inadvertently use a previous one
1190 WSASetLastError( wsaError
);
1196 //===========================================================================================================================
1197 // mDNSPlatformWriteTCP
1198 //===========================================================================================================================
1200 mDNSexport
long mDNSPlatformWriteTCP( TCPSocket
*sock
, const char *inMsg
, unsigned long inMsgSize
)
1205 nsent
= send( sock
->fd
, inMsg
, inMsgSize
, 0 );
1207 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1208 require_noerr( err
, exit
);
1220 //===========================================================================================================================
1221 // mDNSPlatformTCPGetFD
1222 //===========================================================================================================================
1224 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1226 return ( int ) sock
->fd
;
1230 //===========================================================================================================================
1232 //===========================================================================================================================
1234 mStatus
TCPAddSocket( mDNS
* const inMDNS
, TCPSocket
*sock
)
1240 dlog( kDebugLevelChatty
, DEBUG_NAME
"adding TCPSocket 0x%x:%d\n", sock
, sock
->fd
);
1241 err
= TCPBeginRecv( sock
);
1242 require_noerr( err
, exit
);
1250 //===========================================================================================================================
1252 //===========================================================================================================================
1254 mDNSlocal
void TCPDidConnect( mDNS
* const inMDNS
, HANDLE event
, void * context
)
1256 TCPSocket
* sock
= ( TCPSocket
* ) context
;
1257 TCPConnectionCallback callback
= NULL
;
1258 WSANETWORKEVENTS sockEvent
;
1261 if ( inMDNS
->p
->unregisterWaitableEventFunc
)
1263 inMDNS
->p
->unregisterWaitableEventFunc( inMDNS
, event
);
1268 callback
= ( TCPConnectionCallback
) sock
->userCallback
;
1269 err
= WSAEnumNetworkEvents( sock
->fd
, sock
->connectEvent
, &sockEvent
);
1270 require_noerr( err
, exit
);
1271 require_action( sockEvent
.lNetworkEvents
& FD_CONNECT
, exit
, err
= mStatus_UnknownErr
);
1272 require_action( sockEvent
.iErrorCode
[ FD_CONNECT_BIT
] == 0, exit
, err
= sockEvent
.iErrorCode
[ FD_CONNECT_BIT
] );
1274 sock
->connected
= mDNStrue
;
1276 if ( sock
->fd
!= INVALID_SOCKET
)
1278 err
= TCPAddSocket( sock
->m
, sock
);
1279 require_noerr( err
, exit
);
1284 callback( sock
, sock
->userContext
, TRUE
, 0 );
1290 if ( err
&& callback
)
1292 callback( sock
, sock
->userContext
, TRUE
, err
);
1298 //===========================================================================================================================
1300 //===========================================================================================================================
1302 mDNSlocal
void TCPCanRead( TCPSocket
* sock
)
1304 TCPConnectionCallback callback
= ( TCPConnectionCallback
) sock
->userCallback
;
1308 callback( sock
, sock
->userContext
, mDNSfalse
, sock
->lastError
);
1313 //===========================================================================================================================
1315 //===========================================================================================================================
1317 mDNSlocal mStatus
TCPBeginRecv( TCPSocket
* sock
)
1319 DWORD bytesReceived
= 0;
1323 ZeroMemory( &sock
->overlapped
, sizeof( sock
->overlapped
) );
1324 sock
->overlapped
.hEvent
= sock
;
1326 sock
->wbuf
.buf
= ( char* ) sock
->buf
;
1327 sock
->wbuf
.len
= sizeof( sock
->buf
);
1329 err
= WSARecv( sock
->fd
, &sock
->wbuf
, 1, &bytesReceived
, &flags
, &sock
->overlapped
, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE
) TCPEndRecv
);
1330 err
= translate_errno( ( err
== 0 ) || ( WSAGetLastError() == WSA_IO_PENDING
), WSAGetLastError(), kUnknownErr
);
1331 require_noerr( err
, exit
);
1339 //===========================================================================================================================
1341 //===========================================================================================================================
1343 mDNSlocal
void CALLBACK
TCPEndRecv( DWORD error
, DWORD bytesTransferred
, LPWSAOVERLAPPED overlapped
, DWORD flags
)
1349 sock
= ( overlapped
!= NULL
) ? overlapped
->hEvent
: NULL
;
1351 if ( sock
&& ( sock
->fd
!= INVALID_SOCKET
) )
1353 // <rdar://problem/7532492> mDNSResponder gets locking errors on Windows
1355 // There seems to be a bug in WinSock with respect to Alertable I/O. According
1356 // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
1357 // callbacks will only be invoked during the following calls (when the caller sets
1358 // the appropriate flag):
1361 // - WaitForSingleObjectEx
1362 // - WaitForMultipleObjectsEx
1363 // - SignalObjectAndWait
1364 // - MsgWaitForMultipleObjectsEx
1366 // However, we have seen callbacks be invoked during calls to bind() (and maybe others).
1367 // To workaround this, we set the gSocketEventsEnabled flag to be TRUE only when it's okay
1368 // to directly call the readEventHandler. Otherwise we queue the packet up and
1369 // dispatch it later.
1371 if ( gSocketEventsEnabled
&& !gSocketEvents
.Head
)
1373 sock
->lastError
= error
;
1377 if ( bytesTransferred
)
1379 sock
->bptr
= sock
->buf
;
1380 sock
->eptr
= sock
->buf
+ bytesTransferred
;
1384 sock
->closed
= TRUE
;
1388 if ( sock
->readEventHandler
!= NULL
)
1390 // Turn off socket events before calling the readEventHandler.
1391 // This will prevent reentrancy problems.
1393 // Don't forget to reenable socket events afterwards.
1395 SetSocketEventsEnabled( sock
->m
, FALSE
);
1396 sock
->readEventHandler( sock
);
1397 SetSocketEventsEnabled( sock
->m
, TRUE
);
1402 TCPSocketEvent
* event
;
1404 event
= malloc( sizeof( TCPSocketEvent
) );
1405 require_action( event
, exit
, error
= ( DWORD
) kNoMemoryErr
);
1406 event
->super
.sock
= sock
;
1407 event
->super
.handler
= &TCPSocketEventHandler
;
1408 event
->super
.next
= NULL
;
1409 event
->error
= error
;
1410 event
->bytesTransferred
= bytesTransferred
;
1412 if ( bytesTransferred
)
1414 memcpy( event
->buf
, sock
->buf
, bytesTransferred
);
1417 AddToTail( &gSocketEvents
, event
);
1427 //===========================================================================================================================
1428 // mDNSPlatformUDPSocket
1429 //===========================================================================================================================
1431 mDNSexport UDPSocket
* mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
1433 UDPSocket
* sock
= NULL
;
1434 mDNSIPPort port
= requestedport
;
1435 mStatus err
= mStatus_NoError
;
1438 // Setup connection data object
1440 sock
= ( UDPSocket
* ) malloc(sizeof( UDPSocket
) );
1441 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1442 memset( sock
, 0, sizeof( UDPSocket
) );
1444 // Create the socket
1446 sock
->fd
= INVALID_SOCKET
;
1447 sock
->recvMsgPtr
= m
->p
->unicastSock4
.recvMsgPtr
;
1448 sock
->addr
= m
->p
->unicastSock4
.addr
;
1452 // Try at most 10000 times to get a unique random port
1454 for (i
=0; i
<10000; i
++)
1456 struct sockaddr_in saddr
;
1458 saddr
.sin_family
= AF_INET
;
1459 saddr
.sin_addr
.s_addr
= 0;
1461 // The kernel doesn't do cryptographically strong random port
1462 // allocation, so we do it ourselves here
1464 if (mDNSIPPortIsZero(requestedport
))
1466 port
= mDNSOpaque16fromIntVal( ( mDNSu16
) ( 0xC000 + mDNSRandom(0x3FFF) ) );
1469 saddr
.sin_port
= port
.NotAnInteger
;
1471 err
= SetupSocket(m
, ( struct sockaddr
* ) &saddr
, port
, &sock
->fd
);
1475 require_noerr( err
, exit
);
1481 // Arm the completion routine
1483 err
= UDPBeginRecv( sock
);
1484 require_noerr( err
, exit
);
1488 sock
->next
= gUDPSocketList
;
1489 gUDPSocketList
= sock
;
1496 UDPFreeSocket( sock
);
1503 //===========================================================================================================================
1504 // mDNSPlatformUDPClose
1505 //===========================================================================================================================
1507 mDNSexport
void mDNSPlatformUDPClose( UDPSocket
*sock
)
1509 UDPSocket
* current
= gUDPSocketList
;
1510 UDPSocket
* last
= NULL
;
1514 if ( current
== sock
)
1518 gUDPSocketList
= sock
->next
;
1522 last
->next
= sock
->next
;
1525 // Alertable I/O is great, except not so much when it comes to closing
1526 // the socket. Anything that has been previously queued for this socket
1527 // will stay in the queue after you close the socket. This is problematic
1528 // for obvious reasons. So we'll attempt to workaround this by closing
1529 // the socket which will prevent any further queued packets and then not calling
1530 // UDPFreeSocket directly, but by queueing it using QueueUserAPC. The queues
1531 // are FIFO, so that will execute *after* any other previous items in the queue
1533 // UDPEndRecv will check if the socket is valid, and if not, it will ignore
1536 closesocket( sock
->fd
);
1537 sock
->fd
= INVALID_SOCKET
;
1539 QueueUserAPC( ( PAPCFUNC
) UDPFreeSocket
, sock
->m
->p
->mainThread
, ( ULONG_PTR
) sock
);
1540 FreeSocketEventsForSocket( sock
->m
, sock
);
1548 current
= current
->next
;
1553 //===========================================================================================================================
1554 // mDNSPlatformSendUDP
1555 //===========================================================================================================================
1558 mDNSPlatformSendUDP(
1559 const mDNS
* const inMDNS
,
1560 const void * const inMsg
,
1561 const mDNSu8
* const inMsgEnd
,
1562 mDNSInterfaceID inInterfaceID
,
1563 UDPSocket
* inSrcSocket
,
1564 const mDNSAddr
* inDstIP
,
1565 mDNSIPPort inDstPort
)
1567 SOCKET sendingsocket
= INVALID_SOCKET
;
1568 mStatus err
= mStatus_NoError
;
1569 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
1570 struct sockaddr_storage addr
;
1573 DEBUG_USE_ONLY( inMDNS
);
1575 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
1581 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
1583 if( inDstIP
->type
== mDNSAddrType_IPv4
)
1585 struct sockaddr_in
* sa4
;
1587 sa4
= (struct sockaddr_in
*) &addr
;
1588 sa4
->sin_family
= AF_INET
;
1589 sa4
->sin_port
= inDstPort
.NotAnInteger
;
1590 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
1591 sendingsocket
= ifd
? ifd
->sock
.fd
: inMDNS
->p
->unicastSock4
.fd
;
1593 if (inSrcSocket
) { sendingsocket
= inSrcSocket
->fd
; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket
->port
), inMDNS
->p
->unicastSock4
.fd
, sendingsocket
); }
1595 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
1597 struct sockaddr_in6
* sa6
;
1599 sa6
= (struct sockaddr_in6
*) &addr
;
1600 sa6
->sin6_family
= AF_INET6
;
1601 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
1602 sa6
->sin6_flowinfo
= 0;
1603 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
1604 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
1605 sendingsocket
= ifd
? ifd
->sock
.fd
: inMDNS
->p
->unicastSock6
.fd
;
1609 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
1610 err
= mStatus_BadParamErr
;
1614 if (IsValidSocket(sendingsocket
))
1616 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
1617 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
1621 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1623 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
1625 err
= mStatus_TransientErr
;
1629 require_noerr( err
, exit
);
1639 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1642 DEBUG_UNUSED( InterfaceID
);
1645 //===========================================================================================================================
1646 // mDNSPlatformSendRawPacket
1647 //===========================================================================================================================
1649 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
1651 DEBUG_UNUSED( msg
);
1652 DEBUG_UNUSED( end
);
1653 DEBUG_UNUSED( InterfaceID
);
1656 mDNSexport
void mDNSPlatformReceiveRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
1658 DEBUG_UNUSED( msg
);
1659 DEBUG_UNUSED( end
);
1660 DEBUG_UNUSED( InterfaceID
);
1663 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(mDNS
*const m
, const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
1665 DEBUG_UNUSED( tpa
);
1666 DEBUG_UNUSED( tha
);
1667 DEBUG_UNUSED( InterfaceID
);
1670 mDNSexport
void mDNSPlatformWriteDebugMsg(const char *msg
)
1672 dlog( kDebugLevelInfo
, "%s\n", msg
);
1675 mDNSexport
void mDNSPlatformWriteLogMsg( const char * ident
, const char * msg
, mDNSLogLevel_t loglevel
)
1677 extern mDNS mDNSStorage
;
1680 DEBUG_UNUSED( ident
);
1682 type
= EVENTLOG_ERROR_TYPE
;
1686 case MDNS_LOG_MSG
: type
= EVENTLOG_ERROR_TYPE
; break;
1687 case MDNS_LOG_OPERATION
: type
= EVENTLOG_WARNING_TYPE
; break;
1688 case MDNS_LOG_SPS
: type
= EVENTLOG_INFORMATION_TYPE
; break;
1689 case MDNS_LOG_INFO
: type
= EVENTLOG_INFORMATION_TYPE
; break;
1690 case MDNS_LOG_DEBUG
: type
= EVENTLOG_INFORMATION_TYPE
; break;
1692 fprintf(stderr
, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel
);
1696 mDNSStorage
.p
->reportStatusFunc( type
, msg
);
1697 dlog( kDebugLevelInfo
, "%s\n", msg
);
1700 mDNSexport
void mDNSPlatformSourceAddrForDest( mDNSAddr
* const src
, const mDNSAddr
* const dst
)
1702 DEBUG_UNUSED( src
);
1703 DEBUG_UNUSED( dst
);
1706 //===========================================================================================================================
1707 // mDNSPlatformTLSSetupCerts
1708 //===========================================================================================================================
1711 mDNSPlatformTLSSetupCerts(void)
1713 return mStatus_UnsupportedErr
;
1716 //===========================================================================================================================
1717 // mDNSPlatformTLSTearDownCerts
1718 //===========================================================================================================================
1721 mDNSPlatformTLSTearDownCerts(void)
1725 //===========================================================================================================================
1726 // mDNSPlatformSetDNSConfig
1727 //===========================================================================================================================
1729 mDNSlocal
void SetDNSServers( mDNS
*const m
);
1730 mDNSlocal
void SetSearchDomainList( void );
1732 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**regDomains
, DNameListElem
**browseDomains
)
1734 if (setservers
) SetDNSServers(m
);
1735 if (setsearch
) SetSearchDomainList();
1739 GetDDNSFQDN( fqdn
);
1742 if ( browseDomains
)
1744 GetDDNSDomains( browseDomains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
);
1749 GetDDNSDomains( regDomains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
);
1754 //===========================================================================================================================
1755 // mDNSPlatformDynDNSHostNameStatusChanged
1756 //===========================================================================================================================
1759 mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
1761 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1768 ConvertDomainNameToCString(dname
, uname
);
1774 *p
= (char) tolower(*p
);
1775 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1779 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1780 name
= kServiceParametersNode
TEXT("\\DynDNS\\State\\HostNames");
1781 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1782 require_noerr( err
, exit
);
1784 bStatus
= ( status
) ? 0 : 1;
1785 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &bStatus
, sizeof(DWORD
) );
1786 require_noerr( err
, exit
);
1799 //===========================================================================================================================
1801 //===========================================================================================================================
1803 // This routine needs to be called whenever the system secrets database changes.
1804 // We call it from DynDNSConfigDidChange and mDNSPlatformInit
1807 SetDomainSecrets( mDNS
* const m
)
1809 DomainAuthInfo
*ptr
;
1811 DNameListElem
* regDomains
= NULL
;
1813 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
1814 // In the case where the user simultaneously removes their DDNS host name and the key
1815 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
1816 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
1817 // address records behind that we no longer have permission to delete.
1819 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1820 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
1822 GetDDNSFQDN( &fqdn
);
1826 SetDomainSecret( m
, &fqdn
);
1829 GetDDNSDomains( ®Domains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
);
1831 while ( regDomains
)
1833 DNameListElem
* current
= regDomains
;
1834 SetDomainSecret( m
, ¤t
->name
);
1835 regDomains
= regDomains
->next
;
1841 //===========================================================================================================================
1842 // SetSearchDomainList
1843 //===========================================================================================================================
1845 mDNSlocal
void SetDomainFromDHCP( void );
1846 mDNSlocal
void SetReverseMapSearchDomainList( void );
1849 SetSearchDomainList( void )
1851 char * searchList
= NULL
;
1852 DWORD searchListLen
;
1853 //DNameListElem * head = NULL;
1854 //DNameListElem * current = NULL;
1859 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1860 require_noerr( err
, exit
);
1862 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1863 require_noerr( err
, exit
);
1865 // Windows separates the search domains with ','
1867 tok
= strtok( searchList
, "," );
1870 if ( ( strcmp( tok
, "" ) != 0 ) && ( strcmp( tok
, "." ) != 0 ) )
1871 mDNS_AddSearchDomain_CString(tok
);
1872 tok
= strtok( NULL
, "," );
1887 SetDomainFromDHCP();
1888 SetReverseMapSearchDomainList();
1892 //===========================================================================================================================
1893 // SetReverseMapSearchDomainList
1894 //===========================================================================================================================
1897 SetReverseMapSearchDomainList( void )
1899 struct ifaddrs
* ifa
;
1901 ifa
= myGetIfAddrs( 1 );
1906 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1911 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
1913 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1914 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1915 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1916 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1917 mDNS_AddSearchDomain_CString(buffer
);
1921 ifa
= ifa
->ifa_next
;
1928 //===========================================================================================================================
1930 //===========================================================================================================================
1933 SetDNSServers( mDNS
*const m
)
1935 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1936 FIXED_INFO
* fixedInfo
= NULL
;
1938 IP_ADDR_STRING
* dnsServerList
;
1939 IP_ADDR_STRING
* ipAddr
;
1942 mStatus err
= kUnknownErr
;
1944 // Get the primary interface.
1946 index
= GetPrimaryInterface();
1948 // This should have the interface index of the primary index. Fall back in cases where
1949 // it can't be determined.
1955 for ( i
= 0; i
< 100; i
++ )
1957 err
= GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
);
1959 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1964 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1965 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1968 require_noerr( err
, exit
);
1970 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1974 bufLen
= sizeof( FIXED_INFO
);
1976 for ( i
= 0; i
< 100; i
++ )
1980 GlobalFree( fixedInfo
);
1984 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1985 require_action( fixedInfo
, exit
, err
= mStatus_NoMemoryErr
);
1987 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1989 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1995 require_noerr( err
, exit
);
1997 dnsServerList
= &fixedInfo
->DnsServerList
;
2000 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
2003 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
2004 if ( !err
) mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
);
2011 free( pAdapterInfo
);
2016 GlobalFree( fixedInfo
);
2021 //===========================================================================================================================
2022 // SetDomainFromDHCP
2023 //===========================================================================================================================
2026 SetDomainFromDHCP( void )
2029 IP_ADAPTER_INFO
* pAdapterInfo
;
2030 IP_ADAPTER_INFO
* pAdapter
;
2034 LPSTR domain
= NULL
;
2036 mStatus err
= mStatus_NoError
;
2038 pAdapterInfo
= NULL
;
2040 for ( i
= 0; i
< 100; i
++ )
2042 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2044 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2049 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2050 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2053 require_noerr( err
, exit
);
2055 index
= GetPrimaryInterface();
2057 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2059 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2060 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2061 pAdapter
->GatewayList
.IpAddress
.String
&&
2062 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2063 ( !index
|| ( pAdapter
->Index
== index
) ) )
2065 // Found one that will work
2069 _snprintf( keyName
, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter
->AdapterName
);
2071 err
= RegCreateKeyA( HKEY_LOCAL_MACHINE
, keyName
, &key
);
2072 require_noerr( err
, exit
);
2074 err
= RegQueryString( key
, "Domain", &domain
, &dwSize
, NULL
);
2077 if ( !domain
|| !domain
[0] )
2085 err
= RegQueryString( key
, "DhcpDomain", &domain
, &dwSize
, NULL
);
2089 if ( domain
&& domain
[0] ) mDNS_AddSearchDomain_CString(domain
);
2099 free( pAdapterInfo
);
2114 //===========================================================================================================================
2115 // mDNSPlatformGetPrimaryInterface
2116 //===========================================================================================================================
2119 mDNSPlatformGetPrimaryInterface( mDNS
* const m
, mDNSAddr
* v4
, mDNSAddr
* v6
, mDNSAddr
* router
)
2121 IP_ADAPTER_INFO
* pAdapterInfo
;
2122 IP_ADAPTER_INFO
* pAdapter
;
2127 mStatus err
= mStatus_NoError
;
2133 pAdapterInfo
= NULL
;
2137 for ( i
= 0; i
< 100; i
++ )
2139 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2141 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2146 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2147 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2150 require_noerr( err
, exit
);
2152 index
= GetPrimaryInterface();
2154 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2156 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2157 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2158 pAdapter
->GatewayList
.IpAddress
.String
&&
2159 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2160 ( StringToAddress( v4
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
2161 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
2162 ( !index
|| ( pAdapter
->Index
== index
) ) )
2164 // Found one that will work
2166 if ( pAdapter
->AddressLength
== sizeof( m
->PrimaryMAC
) )
2168 memcpy( &m
->PrimaryMAC
, pAdapter
->Address
, pAdapter
->AddressLength
);
2180 free( pAdapterInfo
);
2186 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNS
*const m
, mDNSInterfaceID InterfaceID
, char *EthAddr
, char *IPAddr
, int iteration
)
2199 //===========================================================================================================================
2201 //===========================================================================================================================
2202 #if( MDNS_DEBUGMSGS )
2203 mDNSexport
void debugf_( const char *inFormat
, ... )
2209 va_start( args
, inFormat
);
2210 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2213 dlog( kDebugLevelInfo
, "%s\n", buffer
);
2217 //===========================================================================================================================
2219 //===========================================================================================================================
2221 #if( MDNS_DEBUGMSGS > 1 )
2222 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
2228 va_start( args
, inFormat
);
2229 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2232 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
2239 #pragma mark == Platform Internals ==
2243 //===========================================================================================================================
2245 //===========================================================================================================================
2247 mStatus
SetupNiceName( mDNS
* const inMDNS
)
2249 HKEY descKey
= NULL
;
2253 NETSETUP_JOIN_STATUS joinStatus
;
2260 // Set up the nice name.
2263 // First try and open the registry key that contains the computer description value
2264 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2265 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &descKey
);
2266 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2271 DWORD descSize
= sizeof( desc
);
2273 // look for the computer description
2274 err
= RegQueryValueEx( descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2278 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2287 // if we can't find it in the registry, then use the hostname of the machine
2288 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2290 TCHAR hostname
[256];
2292 namelen
= sizeof( hostname
) / sizeof( TCHAR
);
2294 ok
= GetComputerNameExW( ComputerNamePhysicalDnsHostname
, hostname
, &namelen
);
2295 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2300 err
= TCHARtoUTF8( hostname
, utf8
, sizeof( utf8
) );
2309 // if we can't get the hostname
2310 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2312 // Invalidate name so fall back to a default name.
2314 strcpy( utf8
, kMDNSDefaultName
);
2317 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2318 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2319 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2321 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2325 RegCloseKey( descKey
);
2328 ZeroMemory( inMDNS
->p
->nbname
, sizeof( inMDNS
->p
->nbname
) );
2329 ZeroMemory( inMDNS
->p
->nbdomain
, sizeof( inMDNS
->p
->nbdomain
) );
2331 namelen
= sizeof( inMDNS
->p
->nbname
);
2332 ok
= GetComputerNameExA( ComputerNamePhysicalNetBIOS
, inMDNS
->p
->nbname
, &namelen
);
2334 if ( ok
) dlog( kDebugLevelInfo
, DEBUG_NAME
"netbios name \"%s\"\n", inMDNS
->p
->nbname
);
2336 err
= NetGetJoinInformation( NULL
, &joinName
, &joinStatus
);
2337 check ( err
== NERR_Success
);
2338 if ( err
== NERR_Success
)
2340 if ( ( joinStatus
== NetSetupWorkgroupName
) || ( joinStatus
== NetSetupDomainName
) )
2342 err
= TCHARtoUTF8( joinName
, inMDNS
->p
->nbdomain
, sizeof( inMDNS
->p
->nbdomain
) );
2344 if ( !err
) dlog( kDebugLevelInfo
, DEBUG_NAME
"netbios domain/workgroup \"%s\"\n", inMDNS
->p
->nbdomain
);
2347 NetApiBufferFree( joinName
);
2356 //===========================================================================================================================
2358 //===========================================================================================================================
2360 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2363 char tempString
[ 256 ];
2364 DWORD tempStringLen
;
2365 domainlabel tempLabel
;
2370 // Set up the nice name.
2371 tempString
[ 0 ] = '\0';
2373 // use the hostname of the machine
2374 tempStringLen
= sizeof( tempString
);
2375 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2376 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2379 // if we can't get the hostname
2380 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2382 // Invalidate name so fall back to a default name.
2384 strcpy( tempString
, kMDNSDefaultName
);
2387 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2388 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2389 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2391 // Set up the host name.
2393 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2394 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2396 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2398 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2401 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2403 mDNS_SetFQDN( inMDNS
);
2405 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2410 //===========================================================================================================================
2412 //===========================================================================================================================
2414 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2420 err
= SetupNiceName( inMDNS
);
2423 err
= SetupHostName( inMDNS
);
2430 //===========================================================================================================================
2431 // SetupInterfaceList
2432 //===========================================================================================================================
2434 mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2437 mDNSInterfaceData
** next
;
2438 mDNSInterfaceData
* ifd
;
2439 struct ifaddrs
* addrs
;
2441 struct ifaddrs
* loopbackv4
;
2442 struct ifaddrs
* loopbackv6
;
2447 mDNSBool foundUnicastSock4DestAddr
;
2448 mDNSBool foundUnicastSock6DestAddr
;
2450 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2454 inMDNS
->p
->registeredLoopback4
= mDNSfalse
;
2455 inMDNS
->p
->nextDHCPLeaseExpires
= 0x7FFFFFFF;
2457 foundv4
= mDNSfalse
;
2458 foundv6
= mDNSfalse
;
2459 foundUnicastSock4DestAddr
= mDNSfalse
;
2460 foundUnicastSock6DestAddr
= mDNSfalse
;
2462 // Tear down any existing interfaces that may be set up.
2464 TearDownInterfaceList( inMDNS
);
2466 // Set up the name of this machine.
2468 err
= SetupName( inMDNS
);
2471 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2472 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2474 err
= getifaddrs( &addrs
);
2475 require_noerr( err
, exit
);
2479 next
= &inMDNS
->p
->interfaceList
;
2481 flagMask
= IFF_UP
| IFF_MULTICAST
;
2482 flagTest
= IFF_UP
| IFF_MULTICAST
;
2484 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2485 for( p
= addrs
; p
; p
= p
->ifa_next
)
2487 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2491 if( p
->ifa_flags
& IFF_LOOPBACK
)
2499 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2500 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2502 err
= SetupInterface( inMDNS
, p
, &ifd
);
2503 require_noerr( err
, exit
);
2505 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2506 // register him, but we also want to note that we haven't found a v4 interface
2507 // so that we register loopback so same host operations work
2509 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2514 if ( p
->ifa_dhcpEnabled
&& ( p
->ifa_dhcpLeaseExpires
< inMDNS
->p
->nextDHCPLeaseExpires
) )
2516 inMDNS
->p
->nextDHCPLeaseExpires
= p
->ifa_dhcpLeaseExpires
;
2519 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2520 // of determing the destination address of a packet that is sent to us.
2521 // For multicast packets, that's easy to determine. But for the unicast
2522 // sockets, we'll fake it by taking the address of the first interface
2523 // that is successfully setup.
2525 if ( !foundUnicastSock4DestAddr
)
2527 inMDNS
->p
->unicastSock4
.addr
= ifd
->interfaceInfo
.ip
;
2528 foundUnicastSock4DestAddr
= TRUE
;
2533 ++inMDNS
->p
->interfaceCount
;
2537 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2539 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2540 for( p
= addrs
; p
; p
= p
->ifa_next
)
2542 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2546 if( p
->ifa_flags
& IFF_LOOPBACK
)
2554 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2555 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2557 err
= SetupInterface( inMDNS
, p
, &ifd
);
2558 require_noerr( err
, exit
);
2560 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2561 // register him, but we also want to note that we haven't found a v4 interface
2562 // so that we register loopback so same host operations work
2564 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2569 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2570 // of determing the destination address of a packet that is sent to us.
2571 // For multicast packets, that's easy to determine. But for the unicast
2572 // sockets, we'll fake it by taking the address of the first interface
2573 // that is successfully setup.
2575 if ( !foundUnicastSock6DestAddr
)
2577 inMDNS
->p
->unicastSock6
.addr
= ifd
->interfaceInfo
.ip
;
2578 foundUnicastSock6DestAddr
= TRUE
;
2583 ++inMDNS
->p
->interfaceCount
;
2587 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2589 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2591 flagMask
|= IFF_LOOPBACK
;
2592 flagTest
|= IFF_LOOPBACK
;
2594 for( p
= addrs
; p
; p
= p
->ifa_next
)
2596 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2600 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2611 if ( !foundv4
&& loopbackv4
)
2613 dlog( kDebugLevelInfo
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2614 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2616 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2617 require_noerr( err
, exit
);
2619 inMDNS
->p
->registeredLoopback4
= mDNStrue
;
2621 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2623 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2624 // of determing the destination address of a packet that is sent to us.
2625 // For multicast packets, that's easy to determine. But for the unicast
2626 // sockets, we'll fake it by taking the address of the first interface
2627 // that is successfully setup.
2629 if ( !foundUnicastSock4DestAddr
)
2631 inMDNS
->p
->unicastSock4
.addr
= ifd
->sock
.addr
;
2632 foundUnicastSock4DestAddr
= TRUE
;
2638 ++inMDNS
->p
->interfaceCount
;
2641 if ( !foundv6
&& loopbackv6
)
2643 dlog( kDebugLevelInfo
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2644 loopbackv6
->ifa_name
? loopbackv6
->ifa_name
: "<null>", loopbackv6
->ifa_extra
.index
, loopbackv6
->ifa_addr
);
2646 err
= SetupInterface( inMDNS
, loopbackv6
, &ifd
);
2647 require_noerr( err
, exit
);
2649 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2651 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2652 // of determing the destination address of a packet that is sent to us.
2653 // For multicast packets, that's easy to determine. But for the unicast
2654 // sockets, we'll fake it by taking the address of the first interface
2655 // that is successfully setup.
2657 if ( !foundUnicastSock6DestAddr
)
2659 inMDNS
->p
->unicastSock6
.addr
= ifd
->sock
.addr
;
2660 foundUnicastSock6DestAddr
= TRUE
;
2666 ++inMDNS
->p
->interfaceCount
;
2669 CheckFileShares( inMDNS
);
2674 TearDownInterfaceList( inMDNS
);
2678 freeifaddrs( addrs
);
2680 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2684 //===========================================================================================================================
2685 // TearDownInterfaceList
2686 //===========================================================================================================================
2688 mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2690 mDNSInterfaceData
** p
;
2691 mDNSInterfaceData
* ifd
;
2693 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2697 // Free any pending events received.
2699 FreeSocketEvents( inMDNS
);
2701 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2702 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2703 // so that remove events that occur after an interface goes away can still report the correct interface.
2705 p
= &inMDNS
->p
->inactiveInterfaceList
;
2709 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2715 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2718 QueueUserAPC( ( PAPCFUNC
) FreeInterface
, inMDNS
->p
->mainThread
, ( ULONG_PTR
) ifd
);
2721 // Tear down all the interfaces.
2723 while( inMDNS
->p
->interfaceList
)
2725 ifd
= inMDNS
->p
->interfaceList
;
2726 inMDNS
->p
->interfaceList
= ifd
->next
;
2728 TearDownInterface( inMDNS
, ifd
);
2730 inMDNS
->p
->interfaceCount
= 0;
2732 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2733 return( mStatus_NoError
);
2736 //===========================================================================================================================
2738 //===========================================================================================================================
2740 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2742 mDNSInterfaceData
* ifd
;
2743 mDNSInterfaceData
* p
;
2747 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2751 check( inIFA
->ifa_addr
);
2754 // Allocate memory for the interface and initialize it.
2756 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2757 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2758 ifd
->sock
.fd
= kInvalidSocketRef
;
2759 ifd
->sock
.ifd
= ifd
;
2760 ifd
->sock
.next
= NULL
;
2761 ifd
->sock
.m
= inMDNS
;
2762 ifd
->index
= inIFA
->ifa_extra
.index
;
2763 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2764 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2765 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2766 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2768 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2769 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2771 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2772 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2773 // on a large configured network, which means there's a good chance that most or all the other devices on that
2774 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2775 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2776 // devices on a large configured network, so we are willing to make that sacrifice.
2778 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2779 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2781 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2783 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2785 if (!ifd
->interfaceInfo
.InterfaceID
)
2787 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2790 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2791 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2792 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2794 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2801 if ( !ifd
->interfaceInfo
.InterfaceID
)
2803 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2806 // Set up a socket for this interface (if needed).
2808 if( ifd
->interfaceInfo
.McastTxRx
)
2812 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &ifd
->sock
.fd
);
2813 require_noerr( err
, exit
);
2814 ifd
->sock
.addr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2815 ifd
->sock
.port
= MulticastDNSPort
;
2817 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2819 err
= WSAIoctl( ifd
->sock
.fd
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
), &ifd
->sock
.recvMsgPtr
, sizeof( ifd
->sock
.recvMsgPtr
), &size
, NULL
, NULL
);
2823 ifd
->sock
.recvMsgPtr
= NULL
;
2827 if ( inIFA
->ifa_dhcpEnabled
&& ( inIFA
->ifa_dhcpLeaseExpires
< inMDNS
->p
->nextDHCPLeaseExpires
) )
2829 inMDNS
->p
->nextDHCPLeaseExpires
= inIFA
->ifa_dhcpLeaseExpires
;
2832 ifd
->interfaceInfo
.NetWake
= inIFA
->ifa_womp
;
2834 // Register this interface with mDNS.
2836 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2837 require_noerr( err
, exit
);
2839 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2840 require_noerr( err
, exit
);
2842 memcpy( ifd
->interfaceInfo
.MAC
.b
, inIFA
->ifa_physaddr
, sizeof( ifd
->interfaceInfo
.MAC
.b
) );
2844 ifd
->interfaceInfo
.Advertise
= ( mDNSu8
) inMDNS
->AdvertiseLocalAddresses
;
2846 if ( ifd
->sock
.fd
!= kInvalidSocketRef
)
2848 err
= UDPBeginRecv( &ifd
->sock
);
2849 require_noerr( err
, exit
);
2852 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, mDNSfalse
);
2853 require_noerr( err
, exit
);
2854 ifd
->hostRegistered
= mDNStrue
;
2856 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2867 TearDownInterface( inMDNS
, ifd
);
2869 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2873 //===========================================================================================================================
2874 // TearDownInterface
2875 //===========================================================================================================================
2877 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2882 // Deregister this interface with mDNS.
2884 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2886 if( inIFD
->hostRegistered
)
2888 inIFD
->hostRegistered
= mDNSfalse
;
2889 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
, mDNSfalse
);
2892 // Tear down the multicast socket.
2894 if ( inIFD
->sock
.fd
!= INVALID_SOCKET
)
2896 closesocket( inIFD
->sock
.fd
);
2897 inIFD
->sock
.fd
= INVALID_SOCKET
;
2900 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2901 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2903 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2905 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2906 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2907 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2911 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2912 QueueUserAPC( ( PAPCFUNC
) FreeInterface
, inMDNS
->p
->mainThread
, ( ULONG_PTR
) inIFD
);
2915 return( mStatus_NoError
);
2918 mDNSlocal
void CALLBACK
FreeInterface( mDNSInterfaceData
*inIFD
)
2923 //===========================================================================================================================
2925 //===========================================================================================================================
2927 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2932 DWORD bytesReturned
= 0;
2933 BOOL behavior
= FALSE
;
2935 DEBUG_UNUSED( inMDNS
);
2937 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2939 check( outSocketRef
);
2941 // Set up an IPv4 or IPv6 UDP socket.
2943 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2944 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2945 require_noerr( err
, exit
);
2947 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2948 // if we're creating a multicast socket
2950 if ( port
.NotAnInteger
)
2953 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2954 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2957 // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
2959 // Not sure why, but the default behavior for sockets is to behave incorrectly
2960 // when using them in Overlapped I/O mode on XP. According to MSDN:
2962 // SIO_UDP_CONNRESET (opcode setting: I, T==3)
2963 // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
2964 // Set to FALSE to disable reporting.
2966 // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
2967 // messages were being sent to us after we sent out packets to a multicast address. This is clearly
2968 // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
2969 // will no longer receive any packets from that socket, which is not harmless. This behavior is only
2972 // So we turn off port unreachable reporting to make sure our sockets that are reading
2973 // multicast packets function correctly under all circumstances.
2975 err
= WSAIoctl( sock
, SIO_UDP_CONNRESET
, &behavior
, sizeof(behavior
), NULL
, 0, &bytesReturned
, NULL
, NULL
);
2976 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2978 if( inAddr
->sa_family
== AF_INET
)
2981 struct sockaddr_in sa4
;
2982 struct ip_mreq mreqv4
;
2984 // Bind the socket to the desired port
2986 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2987 mDNSPlatformMemZero( &sa4
, sizeof( sa4
) );
2988 sa4
.sin_family
= AF_INET
;
2989 sa4
.sin_port
= port
.NotAnInteger
;
2990 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2992 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2993 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2995 // Turn on option to receive destination addresses and receiving interface.
2998 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2999 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3001 if (port
.NotAnInteger
)
3003 // Join the all-DNS multicast group so we receive Multicast DNS packets
3005 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
3006 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
3007 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
3008 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3010 // Specify the interface to send multicast packets on this socket.
3012 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
3013 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
3014 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3016 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3019 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3020 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3023 // Send unicast packets with TTL 255 (helps against spoofing).
3026 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
3027 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3029 // Send multicast packets with TTL 255 (helps against spoofing).
3032 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
3033 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3036 else if( inAddr
->sa_family
== AF_INET6
)
3038 struct sockaddr_in6
* sa6p
;
3039 struct sockaddr_in6 sa6
;
3040 struct ipv6_mreq mreqv6
;
3042 sa6p
= (struct sockaddr_in6
*) inAddr
;
3044 // Bind the socket to the desired port
3046 mDNSPlatformMemZero( &sa6
, sizeof( sa6
) );
3047 sa6
.sin6_family
= AF_INET6
;
3048 sa6
.sin6_port
= port
.NotAnInteger
;
3049 sa6
.sin6_flowinfo
= 0;
3050 sa6
.sin6_addr
= sa6p
->sin6_addr
;
3051 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
3053 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
3054 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
3056 // Turn on option to receive destination addresses and receiving interface.
3059 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
3060 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3062 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
3063 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
3064 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
3066 #if( defined( IPV6_V6ONLY ) )
3068 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
3069 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3072 if ( port
.NotAnInteger
)
3074 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3076 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroup_v6
.ip
.v6
);
3077 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
3078 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
3079 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3081 // Specify the interface to send multicast packets on this socket.
3083 option
= (int) sa6p
->sin6_scope_id
;
3084 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
3085 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3087 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3090 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3091 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3094 // Send unicast packets with TTL 255 (helps against spoofing).
3097 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
3098 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3100 // Send multicast packets with TTL 255 (helps against spoofing).
3103 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
3104 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3108 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
3109 err
= kUnsupportedErr
;
3115 *outSocketRef
= sock
;
3116 sock
= kInvalidSocketRef
;
3117 err
= mStatus_NoError
;
3120 if( IsValidSocket( sock
) )
3122 close_compat( sock
);
3127 //===========================================================================================================================
3129 //===========================================================================================================================
3131 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
3138 if( inSA
->sa_family
== AF_INET
)
3140 struct sockaddr_in
* sa4
;
3142 sa4
= (struct sockaddr_in
*) inSA
;
3143 outIP
->type
= mDNSAddrType_IPv4
;
3144 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
3147 outPort
->NotAnInteger
= sa4
->sin_port
;
3149 err
= mStatus_NoError
;
3151 else if( inSA
->sa_family
== AF_INET6
)
3153 struct sockaddr_in6
* sa6
;
3155 sa6
= (struct sockaddr_in6
*) inSA
;
3156 outIP
->type
= mDNSAddrType_IPv6
;
3157 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
3158 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
3160 outIP
->ip
.v6
.w
[ 1 ] = 0;
3164 outPort
->NotAnInteger
= sa6
->sin6_port
;
3166 err
= mStatus_NoError
;
3170 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
3171 err
= mStatus_BadParamErr
;
3181 //===========================================================================================================================
3183 //===========================================================================================================================
3185 mDNSlocal OSStatus
UDPBeginRecv( UDPSocket
* sock
)
3191 require_action( socket
!= NULL
, exit
, err
= kUnknownErr
);
3193 // Initialize the buffer structure
3195 sock
->wbuf
.buf
= (char *) &sock
->packet
;
3196 sock
->wbuf
.len
= (u_long
) sizeof( sock
->packet
);
3197 sock
->srcAddrLen
= sizeof( sock
->srcAddr
);
3199 // Initialize the overlapped structure
3201 ZeroMemory( &sock
->overlapped
, sizeof( OVERLAPPED
) );
3202 sock
->overlapped
.hEvent
= sock
;
3208 if ( sock
->recvMsgPtr
)
3210 sock
->wmsg
.name
= ( LPSOCKADDR
) &sock
->srcAddr
;
3211 sock
->wmsg
.namelen
= sock
->srcAddrLen
;
3212 sock
->wmsg
.lpBuffers
= &sock
->wbuf
;
3213 sock
->wmsg
.dwBufferCount
= 1;
3214 sock
->wmsg
.Control
.buf
= ( CHAR
* ) sock
->controlBuffer
;
3215 sock
->wmsg
.Control
.len
= sizeof( sock
->controlBuffer
);
3216 sock
->wmsg
.dwFlags
= 0;
3218 err
= sock
->recvMsgPtr( sock
->fd
, &sock
->wmsg
, &size
, &sock
->overlapped
, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE
) UDPEndRecv
);
3219 err
= translate_errno( ( err
== 0 ) || ( WSAGetLastError() == WSA_IO_PENDING
), (OSStatus
) WSAGetLastError(), kUnknownErr
);
3221 // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
3223 // There seems to be a bug in some network device drivers that involves calling WSARecvMsg() in
3224 // overlapped i/o mode. Although all the parameters to WSARecvMsg() are correct, it returns a
3225 // WSAEFAULT error code when there is no actual error. We have found experientially that falling
3226 // back to using WSARecvFrom() when this happens will work correctly.
3228 if ( err
== WSAEFAULT
) sock
->recvMsgPtr
= NULL
;
3234 err
= WSARecvFrom( sock
->fd
, &sock
->wbuf
, 1, NULL
, &flags
, ( LPSOCKADDR
) &sock
->srcAddr
, &sock
->srcAddrLen
, &sock
->overlapped
, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE
) UDPEndRecv
);
3235 err
= translate_errno( ( err
== 0 ) || ( WSAGetLastError() == WSA_IO_PENDING
), ( OSStatus
) WSAGetLastError(), kUnknownErr
);
3238 // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
3240 // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
3241 // send operation resulted in an ICMP "Port Unreachable" message."
3243 // Because this is the case, we want to ignore this error and try again. Just in case
3244 // this is some kind of pathological condition, we'll break out of the retry loop
3245 // after 100 iterations
3247 require_action( !err
|| ( err
== WSAECONNRESET
) || ( err
== WSAEFAULT
), exit
, err
= WSAGetLastError() );
3249 while ( ( ( err
== WSAECONNRESET
) || ( err
== WSAEFAULT
) ) && ( numTries
++ < 100 ) );
3255 LogMsg( "WSARecvMsg failed (%d)\n", err
);
3262 //===========================================================================================================================
3264 //===========================================================================================================================
3266 mDNSlocal
void CALLBACK
UDPEndRecv( DWORD err
, DWORD bytesTransferred
, LPWSAOVERLAPPED overlapped
, DWORD flags
)
3268 UDPSocket
* sock
= NULL
;
3272 require_action_quiet( err
!= WSA_OPERATION_ABORTED
, exit
, err
= ( DWORD
) kUnknownErr
);
3273 require_noerr( err
, exit
);
3274 sock
= ( overlapped
!= NULL
) ? overlapped
->hEvent
: NULL
;
3275 require_action( sock
!= NULL
, exit
, err
= ( DWORD
) kUnknownErr
);
3277 // If we've closed the socket, then we want to ignore
3278 // this read. The packet might have been queued before
3279 // the socket was closed.
3281 if ( sock
->fd
!= INVALID_SOCKET
)
3283 const mDNSInterfaceID iid
= sock
->ifd
? sock
->ifd
->interfaceInfo
.InterfaceID
: NULL
;
3290 // Translate the source of this packet into mDNS data types
3292 SockAddrToMDNSAddr( (struct sockaddr
*) &sock
->srcAddr
, &srcAddr
, &srcPort
);
3294 // Initialize the destination of this packet. Just in case
3295 // we can't determine this info because we couldn't call
3296 // WSARecvMsg (recvMsgPtr)
3298 dstAddr
= sock
->addr
;
3299 dstPort
= sock
->port
;
3301 if ( sock
->recvMsgPtr
)
3303 LPWSACMSGHDR header
;
3304 LPWSACMSGHDR last
= NULL
;
3307 // Parse the control information. Reject packets received on the wrong interface.
3309 // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
3311 // There seems to be an interaction between Bullguard and this next bit of code.
3312 // When a user's machine is running Bullguard, the control information that is
3313 // returned is corrupted, and the code would go into an infinite loop. We'll add
3314 // two bits of defensive coding here. The first will check that each pointer to
3315 // the LPWSACMSGHDR that is returned in the for loop is different than the last.
3316 // This fixes the problem with Bullguard. The second will break out of this loop
3317 // after 100 iterations, just in case the corruption isn't caught by the first
3320 for( header
= WSA_CMSG_FIRSTHDR( &sock
->wmsg
); header
; header
= WSA_CMSG_NXTHDR( &sock
->wmsg
, header
) )
3322 if ( ( header
!= last
) && ( ++count
< 100 ) )
3326 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3328 IN_PKTINFO
* ipv4PacketInfo
;
3330 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3332 if ( sock
->ifd
!= NULL
)
3334 require_action( ipv4PacketInfo
->ipi_ifindex
== sock
->ifd
->index
, exit
, err
= ( DWORD
) kMismatchErr
);
3337 dstAddr
.type
= mDNSAddrType_IPv4
;
3338 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3340 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3342 IN6_PKTINFO
* ipv6PacketInfo
;
3344 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3346 if ( sock
->ifd
!= NULL
)
3348 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( sock
->ifd
->index
- kIPv6IfIndexBase
), exit
, err
= ( DWORD
) kMismatchErr
);
3351 dstAddr
.type
= mDNSAddrType_IPv6
;
3352 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3357 static BOOL loggedMessage
= FALSE
;
3359 if ( !loggedMessage
)
3361 LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
3362 loggedMessage
= TRUE
;
3370 // Dispatch the packet to mDNS.
3372 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3373 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", bytesTransferred
);
3374 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3375 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3377 if ( sock
->ifd
!= NULL
)
3379 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &sock
->ifd
->interfaceInfo
.ip
, sock
->ifd
->index
);
3382 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3384 end
= ( (mDNSu8
*) &sock
->packet
) + bytesTransferred
;
3386 // <rdar://problem/7532492> mDNSResponder gets locking errors on Windows
3388 // There seems to be a bug in WinSock with respect to Alertable I/O. According
3389 // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
3390 // callbacks will only be invoked during the following calls (when the caller sets
3391 // the appropriate flag):
3394 // - WaitForSingleObjectEx
3395 // - WaitForMultipleObjectsEx
3396 // - SignalObjectAndWait
3397 // - MsgWaitForMultipleObjectsEx
3399 // However, we have seen callbacks be invoked during calls to bind() (and maybe others).
3400 // To workaround this, we set the gSocketEventsEnabled flag to be TRUE only when it's okay
3401 // to directly call mDNSCoreReceive. Otherwise we queue the packet up and dispatch it later.
3403 if ( gSocketEventsEnabled
&& !gSocketEvents
.Head
)
3405 // Turn off socket events before calling mDNSCoreReceive().
3406 // This will prevent reentrancy problems.
3408 // Don't forget to reenable socket events afterwards.
3410 SetSocketEventsEnabled( sock
->m
, FALSE
);
3411 mDNSCoreReceive( sock
->m
, &sock
->packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3412 SetSocketEventsEnabled( sock
->m
, TRUE
);
3416 UDPSocketEvent
* event
;
3418 event
= malloc( sizeof( UDPSocketEvent
) );
3419 require_action( event
, exit
, err
= ( DWORD
) kNoMemoryErr
);
3420 event
->super
.sock
= sock
;
3421 event
->super
.handler
= &UDPSocketEventHandler
;
3422 event
->super
.next
= NULL
;
3424 memcpy( &event
->packet
, &sock
->packet
, sizeof( event
->packet
) );
3425 event
->end
= ( (mDNSu8
*) &event
->packet
) + bytesTransferred
;
3426 event
->srcAddr
= srcAddr
;
3427 event
->dstAddr
= dstAddr
;
3428 event
->srcPort
= srcPort
;
3429 event
->dstPort
= dstPort
;
3431 AddToTail( &gSocketEvents
, event
);
3437 // If the socket is still good, then start up another asynchronous read
3439 if ( sock
&& ( sock
->fd
!= INVALID_SOCKET
) )
3441 err
= UDPBeginRecv( sock
);
3447 //===========================================================================================================================
3448 // InterfaceListDidChange
3449 //===========================================================================================================================
3450 void InterfaceListDidChange( mDNS
* const inMDNS
)
3454 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3457 // Tear down the existing interfaces and set up new ones using the new IP info.
3459 err
= TearDownInterfaceList( inMDNS
);
3462 err
= SetupInterfaceList( inMDNS
);
3465 err
= uDNS_SetupDNSConfig( inMDNS
);
3468 // Inform clients of the change.
3470 mDNS_ConfigChanged(inMDNS
);
3472 // Force mDNS to update.
3474 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
); // What is this for? Mac OS X does not do this
3478 //===========================================================================================================================
3479 // ComputerDescriptionDidChange
3480 //===========================================================================================================================
3481 void ComputerDescriptionDidChange( mDNS
* const inMDNS
)
3483 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3487 SetupNiceName( inMDNS
);
3491 //===========================================================================================================================
3492 // TCPIPConfigDidChange
3493 //===========================================================================================================================
3494 void TCPIPConfigDidChange( mDNS
* const inMDNS
)
3498 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3501 err
= uDNS_SetupDNSConfig( inMDNS
);
3506 //===========================================================================================================================
3507 // DynDNSConfigDidChange
3508 //===========================================================================================================================
3509 void DynDNSConfigDidChange( mDNS
* const inMDNS
)
3513 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3516 SetDomainSecrets( inMDNS
);
3518 err
= uDNS_SetupDNSConfig( inMDNS
);
3523 //===========================================================================================================================
3524 // FileSharingDidChange
3525 //===========================================================================================================================
3526 void FileSharingDidChange( mDNS
* const inMDNS
)
3528 dlog( kDebugLevelInfo
, DEBUG_NAME
"File shares has changed\n" );
3531 CheckFileShares( inMDNS
);
3535 //===========================================================================================================================
3536 // FilewallDidChange
3537 //===========================================================================================================================
3538 void FirewallDidChange( mDNS
* const inMDNS
)
3540 dlog( kDebugLevelInfo
, DEBUG_NAME
"Firewall has changed\n" );
3543 CheckFileShares( inMDNS
);
3549 #pragma mark == Utilities ==
3552 //===========================================================================================================================
3554 //===========================================================================================================================
3556 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
)
3560 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3562 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3563 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3565 if( !gIPHelperLibraryInstance
)
3567 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
3568 if( gIPHelperLibraryInstance
)
3570 gGetAdaptersAddressesFunctionPtr
=
3571 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
3572 if( !gGetAdaptersAddressesFunctionPtr
)
3576 ok
= FreeLibrary( gIPHelperLibraryInstance
);
3577 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
3578 gIPHelperLibraryInstance
= NULL
;
3583 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3584 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
3585 // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
3587 if( !gGetAdaptersAddressesFunctionPtr
|| ( ( ( err
= getifaddrs_ipv6( outAddrs
) ) != mStatus_NoError
) || ( ( outAddrs
!= NULL
) && ( *outAddrs
== NULL
) ) ) )
3589 err
= getifaddrs_ipv4( outAddrs
);
3590 require_noerr( err
, exit
);
3595 err
= getifaddrs_ipv4( outAddrs
);
3596 require_noerr( err
, exit
);
3604 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3605 //===========================================================================================================================
3607 //===========================================================================================================================
3609 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
3614 struct ifaddrs
* head
;
3615 struct ifaddrs
** next
;
3616 IP_ADAPTER_ADDRESSES
* iaaList
;
3618 IP_ADAPTER_ADDRESSES
* iaa
;
3620 struct ifaddrs
* ifa
;
3622 check( gGetAdaptersAddressesFunctionPtr
);
3628 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3629 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3630 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3632 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
3637 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
3638 check( err
== ERROR_BUFFER_OVERFLOW
);
3639 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
3641 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
3642 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
3644 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
3645 if( err
== ERROR_SUCCESS
) break;
3650 require( i
< 100, exit
);
3651 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
3654 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
3657 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
3659 IP_ADAPTER_PREFIX
* firstPrefix
;
3661 if( iaa
->IfIndex
> 0xFFFFFF )
3663 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
3665 if( iaa
->Ipv6IfIndex
> 0xFF )
3667 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
3670 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3671 // following code to crash when iterating through the prefix list. This seems
3672 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3673 // This shouldn't happen according to Microsoft docs which states:
3675 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3677 // So the data structure seems to be corrupted when we return from
3678 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3679 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3680 // modify iaa to have the correct values.
3682 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
3684 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
3685 firstPrefix
= iaa
->FirstPrefix
;
3693 // Skip pseudo and tunnel interfaces.
3695 if( ( ( ipv6IfIndex
== 1 ) && ( iaa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
) ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
3700 // Add each address as a separate interface to emulate the way getifaddrs works.
3702 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
3706 IP_ADAPTER_PREFIX
* prefix
;
3709 struct sockaddr_in ipv4Netmask
;
3711 family
= addr
->Address
.lpSockaddr
->sa_family
;
3712 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
3714 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3715 // Seems as if the problem here is a buggy implementation of some network interface
3716 // driver. It is reporting that is has a link-local address when it is actually
3717 // disconnected. This was causing a problem in AddressToIndexAndMask.
3718 // The solution is to call AddressToIndexAndMask first, and if unable to lookup
3719 // the address, to ignore that address.
3722 memset( &ipv4Netmask
, 0, sizeof( ipv4Netmask
) );
3724 if ( family
== AF_INET
)
3726 err
= AddressToIndexAndMask( addr
->Address
.lpSockaddr
, &ipv4Index
, ( struct sockaddr
* ) &ipv4Netmask
);
3735 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3736 require_action( ifa
, exit
, err
= WSAENOBUFS
);
3739 next
= &ifa
->ifa_next
;
3743 size
= strlen( iaa
->AdapterName
) + 1;
3744 ifa
->ifa_name
= (char *) malloc( size
);
3745 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
3746 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
3748 // Get interface flags.
3751 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
3752 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
3753 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
3754 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
3757 // <rdar://problem/4045657> Interface index being returned is 512
3759 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
3760 // This code used to shift the IPv4 index up to ensure uniqueness between
3761 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
3762 // then see interface indexes passed back that don't correspond to anything
3763 // that is seen in Win32 APIs or command line tools like "route". As a relatively
3764 // small percentage of developers are actively using IPv6, it seems to
3765 // make sense to make our use of IPv4 as confusion free as possible.
3766 // So now, IPv6 interface indexes will be shifted up by a
3767 // constant value which will serve to uniquely identify them, and we will
3768 // leave IPv4 interface indexes unmodified.
3772 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
3773 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
3777 // Get lease lifetime
3779 if ( ( iaa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
) && ( addr
->LeaseLifetime
!= 0 ) && ( addr
->ValidLifetime
!= 0xFFFFFFFF ) )
3781 ifa
->ifa_dhcpEnabled
= TRUE
;
3782 ifa
->ifa_dhcpLeaseExpires
= time( NULL
) + addr
->ValidLifetime
;
3786 ifa
->ifa_dhcpEnabled
= FALSE
;
3787 ifa
->ifa_dhcpLeaseExpires
= 0;
3790 if ( iaa
->PhysicalAddressLength
== sizeof( ifa
->ifa_physaddr
) )
3792 memcpy( ifa
->ifa_physaddr
, iaa
->PhysicalAddress
, iaa
->PhysicalAddressLength
);
3795 // Because we don't get notified of womp changes, we're going to just assume
3796 // that all wired interfaces have it enabled. Before we go to sleep, we'll check
3797 // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
3800 ifa
->ifa_womp
= ( iaa
->IfType
== IF_TYPE_ETHERNET_CSMACD
) ? mDNStrue
: mDNSfalse
;
3808 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
3809 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
3810 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
3816 check( ifa
->ifa_addr
);
3818 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
3821 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
3823 if( ( prefix
->Address
.lpSockaddr
->sa_family
== family
) && ( prefixIndex
== addrIndex
) )
3825 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
3826 prefixLength
= prefix
->PrefixLength
;
3834 struct sockaddr_in
* sa4
;
3836 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
3837 require_action( sa4
, exit
, err
= WSAENOBUFS
);
3838 sa4
->sin_family
= AF_INET
;
3839 sa4
->sin_addr
.s_addr
= ipv4Netmask
.sin_addr
.s_addr
;
3841 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
3842 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
3848 struct sockaddr_in6
* sa6
;
3853 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
3855 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
3856 require_action( sa6
, exit
, err
= WSAENOBUFS
);
3857 sa6
->sin6_family
= AF_INET6
;
3859 if( prefixLength
== 0 )
3861 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
3865 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
3867 if( len
>= 8 ) maskByte
= 0xFF;
3868 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
3869 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
3871 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
3888 err
= ERROR_SUCCESS
;
3893 freeifaddrs( head
);
3899 return( (int) err
);
3902 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
3904 //===========================================================================================================================
3906 //===========================================================================================================================
3908 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
3914 INTERFACE_INFO
* buffer
;
3915 INTERFACE_INFO
* tempBuffer
;
3916 INTERFACE_INFO
* ifInfo
;
3919 struct ifaddrs
* head
;
3920 struct ifaddrs
** next
;
3921 struct ifaddrs
* ifa
;
3923 sock
= INVALID_SOCKET
;
3928 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
3929 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
3930 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
3932 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3933 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
3934 require_noerr( err
, exit
);
3937 size
= 16 * sizeof( INTERFACE_INFO
);
3940 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
3941 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
3942 buffer
= tempBuffer
;
3944 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
3951 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
3953 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
3955 check( actualSize
<= size
);
3956 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
3957 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
3959 // Process the raw interface list and build a linked list of IPv4 interfaces.
3961 for( i
= 0; i
< n
; ++i
)
3964 struct sockaddr_in netmask
;
3966 ifInfo
= &buffer
[ i
];
3967 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
3972 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3973 // See comment in getifaddrs_ipv6
3976 memset( &netmask
, 0, sizeof( netmask
) );
3977 err
= AddressToIndexAndMask( ( struct sockaddr
* ) &ifInfo
->iiAddress
.AddressIn
, &ifIndex
, ( struct sockaddr
* ) &netmask
);
3984 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3985 require_action( ifa
, exit
, err
= WSAENOBUFS
);
3988 next
= &ifa
->ifa_next
;
3992 ifa
->ifa_name
= (char *) malloc( 16 );
3993 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
3994 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
3996 // Get interface flags.
3998 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4002 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
4004 struct sockaddr_in
* sa4
;
4006 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4007 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4008 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4009 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4011 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4012 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4014 // <rdar://problem/4076478> Service won't start on Win2K. The address
4015 // family field was not being initialized.
4017 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4018 ( ( struct sockaddr_in
* ) ifa
->ifa_netmask
)->sin_addr
= netmask
.sin_addr
;
4019 ifa
->ifa_extra
.index
= ifIndex
;
4023 // Emulate an interface index.
4025 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4042 freeifaddrs( head
);
4048 if( sock
!= INVALID_SOCKET
)
4050 closesocket( sock
);
4055 //===========================================================================================================================
4057 //===========================================================================================================================
4059 mDNSlocal
void freeifaddrs( struct ifaddrs
*inIFAs
)
4064 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4066 for( p
= inIFAs
; p
; p
= q
)
4072 free( p
->ifa_name
);
4077 free( p
->ifa_addr
);
4080 if( p
->ifa_netmask
)
4082 free( p
->ifa_netmask
);
4083 p
->ifa_netmask
= NULL
;
4085 if( p
->ifa_broadaddr
)
4087 free( p
->ifa_broadaddr
);
4088 p
->ifa_broadaddr
= NULL
;
4090 if( p
->ifa_dstaddr
)
4092 free( p
->ifa_dstaddr
);
4093 p
->ifa_dstaddr
= NULL
;
4097 free( p
->ifa_data
);
4105 //===========================================================================================================================
4106 // GetPrimaryInterface
4107 //===========================================================================================================================
4110 GetPrimaryInterface()
4112 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4114 BOOL bOrder
= FALSE
;
4118 unsigned long int i
;
4120 // Find out how big our buffer needs to be.
4122 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4123 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4125 // Allocate the memory for the table
4127 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4128 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4130 // Now get the table.
4132 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4133 require_noerr( err
, exit
);
4136 // Search for the row in the table we want.
4138 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4140 // Look for a default route
4142 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4144 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4149 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4150 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4156 if ( pIpForwardTable
!= NULL
)
4158 free( pIpForwardTable
);
4165 //===========================================================================================================================
4166 // AddressToIndexAndMask
4167 //===========================================================================================================================
4170 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4172 // Before calling AddIPAddress we use GetIpAddrTable to get
4173 // an adapter to which we can add the IP.
4175 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4177 mStatus err
= mStatus_UnknownErr
;
4180 // For now, this is only for IPv4 addresses. That is why we can safely cast
4181 // addr's to sockaddr_in.
4183 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4185 // Make an initial call to GetIpAddrTable to get the
4186 // necessary size into the dwSize variable
4188 for ( i
= 0; i
< 100; i
++ )
4190 err
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
4192 if ( err
!= ERROR_INSUFFICIENT_BUFFER
)
4197 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4198 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4201 require_noerr( err
, exit
);
4202 err
= mStatus_UnknownErr
;
4204 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4206 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4208 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4209 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4210 err
= mStatus_NoError
;
4219 free( pIPAddrTable
);
4226 //===========================================================================================================================
4227 // CanReceiveUnicast
4228 //===========================================================================================================================
4230 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4234 struct sockaddr_in addr
;
4236 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4238 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4239 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4240 ok
= IsValidSocket( sock
);
4243 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
4244 addr
.sin_family
= AF_INET
;
4245 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4246 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4248 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4249 close_compat( sock
);
4252 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4257 //===========================================================================================================================
4259 //===========================================================================================================================
4261 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4263 struct ifaddrs
* addrs
= NULL
;
4264 struct ifaddrs
* p
= NULL
;
4266 mDNSBool ret
= mDNSfalse
;
4268 // For now, only works for IPv4 interfaces
4270 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4272 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4274 err
= getifaddrs_ipv4( &addrs
);
4275 require_noerr( err
, exit
);
4277 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4279 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4280 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4282 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4292 freeifaddrs( addrs
);
4299 //===========================================================================================================================
4300 // GetWindowsVersionString
4301 //===========================================================================================================================
4303 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4305 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4306 #define VER_PLATFORM_WIN32_CE 3
4310 OSVERSIONINFO osInfo
;
4312 const char * versionString
;
4318 versionString
= "unknown Windows version";
4320 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4321 ok
= GetVersionEx( &osInfo
);
4322 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4323 require_noerr( err
, exit
);
4325 platformID
= osInfo
.dwPlatformId
;
4326 majorVersion
= osInfo
.dwMajorVersion
;
4327 minorVersion
= osInfo
.dwMinorVersion
;
4328 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4330 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4332 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4334 versionString
= "Windows 95";
4336 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4338 versionString
= "Windows 95 SP1";
4340 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4342 versionString
= "Windows 95 OSR2";
4344 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4346 versionString
= "Windows 98";
4348 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4350 versionString
= "Windows 98 SP1";
4352 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4354 versionString
= "Windows 98 SE";
4356 else if( minorVersion
== 90 )
4358 versionString
= "Windows ME";
4361 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4363 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4365 versionString
= "Windows NT 3.51";
4367 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4369 versionString
= "Windows NT 4";
4371 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4373 versionString
= "Windows 2000";
4375 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4377 versionString
= "Windows XP";
4379 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4381 versionString
= "Windows Server 2003";
4384 else if( platformID
== VER_PLATFORM_WIN32_CE
)
4386 versionString
= "Windows CE";
4390 if( inBuffer
&& ( inBufferSize
> 0 ) )
4393 strncpy( inBuffer
, versionString
, inBufferSize
);
4394 inBuffer
[ inBufferSize
] = '\0';
4400 //===========================================================================================================================
4402 //===========================================================================================================================
4405 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
4411 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
4422 *string
= (char*) malloc( *stringLen
);
4423 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
4425 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
4429 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
4431 require_noerr_quiet( err
, exit
);
4435 DWORD dwSize
= sizeof( DWORD
);
4437 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
4449 //===========================================================================================================================
4451 //===========================================================================================================================
4453 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
4455 struct sockaddr_in6 sa6
;
4456 struct sockaddr_in sa4
;
4460 sa6
.sin6_family
= AF_INET6
;
4461 dwSize
= sizeof( sa6
);
4463 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
4465 if ( err
== mStatus_NoError
)
4467 err
= SetupAddr( ip
, (struct sockaddr
*) &sa6
);
4468 require_noerr( err
, exit
);
4472 sa4
.sin_family
= AF_INET
;
4473 dwSize
= sizeof( sa4
);
4475 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
4476 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
4477 require_noerr( err
, exit
);
4479 err
= SetupAddr( ip
, (struct sockaddr
*) &sa4
);
4480 require_noerr( err
, exit
);
4489 //===========================================================================================================================
4491 //===========================================================================================================================
4493 mDNSlocal
struct ifaddrs
*
4494 myGetIfAddrs(int refresh
)
4496 static struct ifaddrs
*ifa
= NULL
;
4513 //===========================================================================================================================
4515 //===========================================================================================================================
4518 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
4520 #if( defined( UNICODE ) || defined( _UNICODE ) )
4524 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4525 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4526 require_noerr( err
, exit
);
4531 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
4536 //===========================================================================================================================
4537 // WindowsLatin1toUTF8
4538 //===========================================================================================================================
4541 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
4549 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4551 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
4552 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4553 require_noerr( err
, exit
);
4555 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
4556 require_action( utf16
, exit
, err
= kNoMemoryErr
);
4558 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
4559 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4560 require_noerr( err
, exit
);
4562 // Now convert the temporary UTF-16 to UTF-8.
4564 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4565 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4566 require_noerr( err
, exit
);
4569 if( utf16
) free( utf16
);
4574 //===========================================================================================================================
4576 //===========================================================================================================================
4578 mDNSlocal
void CALLBACK
4579 TCPFreeSocket( TCPSocket
*sock
)
4583 dlog( kDebugLevelChatty
, DEBUG_NAME
"freeing TCPSocket 0x%x:%d\n", sock
, sock
->fd
);
4585 if ( sock
->connectEvent
)
4587 CloseHandle( sock
->connectEvent
);
4588 sock
->connectEvent
= NULL
;
4591 if ( sock
->fd
!= INVALID_SOCKET
)
4593 closesocket( sock
->fd
);
4594 sock
->fd
= INVALID_SOCKET
;
4601 //===========================================================================================================================
4603 //===========================================================================================================================
4605 mDNSlocal
void CALLBACK
4606 UDPFreeSocket( UDPSocket
* sock
)
4610 dlog( kDebugLevelChatty
, DEBUG_NAME
"freeing UDPSocket %d (%##a)\n", sock
->fd
, &sock
->addr
);
4612 if ( sock
->fd
!= INVALID_SOCKET
)
4614 closesocket( sock
->fd
);
4615 sock
->fd
= INVALID_SOCKET
;
4621 //===========================================================================================================================
4623 //===========================================================================================================================
4625 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
4627 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
4629 if (sa
->sa_family
== AF_INET
)
4631 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
4632 ip
->type
= mDNSAddrType_IPv4
;
4633 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
4634 return(mStatus_NoError
);
4637 if (sa
->sa_family
== AF_INET6
)
4639 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
4640 ip
->type
= mDNSAddrType_IPv6
;
4641 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.u
.Word
[1] = 0;
4642 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
4643 return(mStatus_NoError
);
4646 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
4647 return(mStatus_Invalid
);
4651 mDNSlocal
void GetDDNSFQDN( domainname
*const fqdn
)
4665 // Get info from Bonjour registry key
4667 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
4668 require_noerr( err
, exit
);
4670 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
4671 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
4673 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
4675 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
4696 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCWSTR lpSubKey
)
4698 mDNSlocal
void GetDDNSConfig( DNameListElem
** domains
, LPCSTR lpSubKey
)
4701 char subKeyName
[kRegistryMaxKeyLength
+ 1];
4718 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, lpSubKey
, &key
);
4719 require_noerr( err
, exit
);
4721 // Get information about this node
4723 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
4724 require_noerr( err
, exit
);
4726 for ( i
= 0; i
< cSubKeys
; i
++)
4730 dwSize
= kRegistryMaxKeyLength
;
4732 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
4736 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
4737 require_noerr( err
, exit
);
4739 dwSize
= sizeof( DWORD
);
4740 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
4742 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
4744 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
4746 dlog( kDebugLevelError
, "bad DDNS domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
4750 DNameListElem
* domain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
4751 require_action( domain
, exit
, err
= mStatus_NoMemoryErr
);
4753 AssignDomainName(&domain
->name
, &dname
);
4754 domain
->next
= *domains
;
4760 RegCloseKey( subKey
);
4769 RegCloseKey( subKey
);
4779 mDNSlocal
void SetDomainSecret( mDNS
* const m
, const domainname
* inDomain
)
4781 char domainUTF8
[ 256 ];
4782 DomainAuthInfo
*foundInList
;
4783 DomainAuthInfo
*ptr
;
4784 char outDomain
[ 256 ];
4786 char outSecret
[ 256 ];
4789 ConvertDomainNameToCString( inDomain
, domainUTF8
);
4791 // If we're able to find a secret for this domain
4793 if ( LsaGetSecret( domainUTF8
, outDomain
, sizeof( outDomain
), outKey
, sizeof( outKey
), outSecret
, sizeof( outSecret
) ) )
4798 // Tell the core about this secret
4800 MakeDomainNameFromDNSNameString( &domain
, outDomain
);
4801 MakeDomainNameFromDNSNameString( &key
, outKey
);
4803 for (foundInList
= m
->AuthInfoList
; foundInList
; foundInList
= foundInList
->next
)
4804 if (SameDomainName(&foundInList
->domain
, &domain
) ) break;
4810 ptr
= (DomainAuthInfo
*)malloc(sizeof(DomainAuthInfo
));
4811 require_action( ptr
, exit
, err
= mStatus_NoMemoryErr
);
4814 err
= mDNS_SetSecretForDomain(m
, ptr
, &domain
, &key
, outSecret
, mDNSfalse
);
4815 require_action( err
!= mStatus_BadParamErr
, exit
, if (!foundInList
) mDNSPlatformMemFree( ptr
) );
4817 debugf("Setting shared secret for zone %s with key %##s", outDomain
, key
.c
);
4826 mDNSlocal VOID CALLBACK
4827 CheckFileSharesProc( LPVOID arg
, DWORD dwTimerLowValue
, DWORD dwTimerHighValue
)
4829 mDNS
* const m
= ( mDNS
* const ) arg
;
4831 ( void ) dwTimerLowValue
;
4832 ( void ) dwTimerHighValue
;
4834 CheckFileShares( m
);
4838 mDNSlocal
unsigned __stdcall
4839 SMBRegistrationThread( void * arg
)
4841 mDNS
* const m
= ( mDNS
* const ) arg
;
4842 DNSServiceRef sref
= NULL
;
4843 HANDLE handles
[ 3 ];
4844 mDNSu8 txtBuf
[ 256 ];
4848 mDNSIPPort port
= { { SMBPortAsNumber
>> 8, SMBPortAsNumber
& 0xFF } };
4849 DNSServiceErrorType err
;
4851 DEBUG_UNUSED( arg
);
4853 handles
[ 0 ] = gSMBThreadStopEvent
;
4854 handles
[ 1 ] = gSMBThreadRegisterEvent
;
4855 handles
[ 2 ] = gSMBThreadDeregisterEvent
;
4857 memset( txtBuf
, 0, sizeof( txtBuf
) );
4859 keyLen
= strlen( "netbios=" );
4860 valLen
= strlen( m
->p
->nbname
);
4861 require_action( valLen
< 32, exit
, err
= kUnknownErr
); // This should never happen, but check to avoid further memory corruption
4862 *txtPtr
++ = ( mDNSu8
) ( keyLen
+ valLen
);
4863 memcpy( txtPtr
, "netbios=", keyLen
);
4865 if ( valLen
) { memcpy( txtPtr
, m
->p
->nbname
, valLen
); txtPtr
+= ( mDNSu8
) valLen
; }
4866 keyLen
= strlen( "domain=" );
4867 valLen
= strlen( m
->p
->nbdomain
);
4868 require_action( valLen
< 32, exit
, err
= kUnknownErr
); // This should never happen, but check to avoid further memory corruption
4869 *txtPtr
++ = ( mDNSu8
)( keyLen
+ valLen
);
4870 memcpy( txtPtr
, "domain=", keyLen
);
4872 if ( valLen
) { memcpy( txtPtr
, m
->p
->nbdomain
, valLen
); txtPtr
+= valLen
; }
4878 ret
= WaitForMultipleObjects( 3, handles
, FALSE
, INFINITE
);
4880 if ( ret
!= WAIT_FAILED
)
4882 if ( ret
== kSMBStopEvent
)
4886 else if ( ret
== kSMBRegisterEvent
)
4888 err
= gDNSServiceRegister( &sref
, 0, 0, NULL
, "_smb._tcp,_file", NULL
, NULL
, ( uint16_t ) port
.NotAnInteger
, ( mDNSu16
)( txtPtr
- txtBuf
), txtBuf
, NULL
, NULL
);
4892 LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err
);
4897 else if ( ret
== kSMBDeregisterEvent
)
4901 gDNSServiceRefDeallocate( sref
);
4908 LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
4917 gDNSServiceRefDeallocate( sref
);
4921 SetEvent( gSMBThreadQuitEvent
);
4928 CheckFileShares( mDNS
* const m
)
4930 PSHARE_INFO_1 bufPtr
= ( PSHARE_INFO_1
) NULL
;
4931 DWORD entriesRead
= 0;
4932 DWORD totalEntries
= 0;
4934 mDNSBool advertise
= mDNSfalse
;
4935 mDNSBool fileSharing
= mDNSfalse
;
4936 mDNSBool printSharing
= mDNSfalse
;
4944 // Only do this if we're not shutting down
4946 require_action_quiet( m
->AdvertiseLocalAddresses
&& !m
->ShutdownTime
, exit
, err
= kNoErr
);
4948 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\Services\\SMB", &key
);
4952 DWORD dwSize
= sizeof( DWORD
);
4953 RegQueryValueEx( key
, L
"Advertise", NULL
, NULL
, (LPBYTE
) &advertise
, &dwSize
);
4956 if ( advertise
&& mDNSIsFileAndPrintSharingEnabled( &retry
) )
4958 dlog( kDebugLevelTrace
, DEBUG_NAME
"Sharing is enabled\n" );
4960 res
= NetShareEnum( NULL
, 1, ( LPBYTE
* )&bufPtr
, MAX_PREFERRED_LENGTH
, &entriesRead
, &totalEntries
, &resume
);
4962 if ( ( res
== ERROR_SUCCESS
) || ( res
== ERROR_MORE_DATA
) )
4964 PSHARE_INFO_1 p
= bufPtr
;
4967 for( i
= 0; i
< entriesRead
; i
++ )
4969 // We are only interested if the user is sharing anything other
4970 // than the built-in "print$" source
4972 if ( ( p
->shi1_type
== STYPE_DISKTREE
) && ( wcscmp( p
->shi1_netname
, TEXT( "print$" ) ) != 0 ) )
4974 fileSharing
= mDNStrue
;
4976 else if ( p
->shi1_type
== STYPE_PRINTQ
)
4978 printSharing
= mDNStrue
;
4984 NetApiBufferFree( bufPtr
);
4988 else if ( res
== NERR_ServerNotStarted
)
4997 LARGE_INTEGER liTimeout
;
4999 qwTimeout
= -m
->p
->checkFileSharesTimeout
* 10000000;
5000 liTimeout
.LowPart
= ( DWORD
)( qwTimeout
& 0xFFFFFFFF );
5001 liTimeout
.HighPart
= ( LONG
)( qwTimeout
>> 32 );
5003 SetWaitableTimer( m
->p
->checkFileSharesTimer
, &liTimeout
, 0, CheckFileSharesProc
, m
, FALSE
);
5006 if ( !m
->p
->smbFileSharing
&& fileSharing
)
5010 if ( !gDNSSDLibrary
)
5012 gDNSSDLibrary
= LoadLibrary( TEXT( "dnssd.dll" ) );
5013 require_action( gDNSSDLibrary
, exit
, err
= GetLastError() );
5016 if ( !gDNSServiceRegister
)
5018 gDNSServiceRegister
= ( DNSServiceRegisterFunc
) GetProcAddress( gDNSSDLibrary
, "DNSServiceRegister" );
5019 require_action( gDNSServiceRegister
, exit
, err
= GetLastError() );
5022 if ( !gDNSServiceRefDeallocate
)
5024 gDNSServiceRefDeallocate
= ( DNSServiceRefDeallocateFunc
) GetProcAddress( gDNSSDLibrary
, "DNSServiceRefDeallocate" );
5025 require_action( gDNSServiceRefDeallocate
, exit
, err
= GetLastError() );
5028 if ( !gSMBThreadRegisterEvent
)
5030 gSMBThreadRegisterEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5031 require_action( gSMBThreadRegisterEvent
!= NULL
, exit
, err
= GetLastError() );
5034 if ( !gSMBThreadDeregisterEvent
)
5036 gSMBThreadDeregisterEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5037 require_action( gSMBThreadDeregisterEvent
!= NULL
, exit
, err
= GetLastError() );
5040 if ( !gSMBThreadStopEvent
)
5042 gSMBThreadStopEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5043 require_action( gSMBThreadStopEvent
!= NULL
, exit
, err
= GetLastError() );
5046 if ( !gSMBThreadQuitEvent
)
5048 gSMBThreadQuitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5049 require_action( gSMBThreadQuitEvent
!= NULL
, exit
, err
= GetLastError() );
5052 gSMBThread
= ( HANDLE
) _beginthreadex( NULL
, 0, SMBRegistrationThread
, m
, 0, NULL
);
5053 require_action( gSMBThread
!= NULL
, exit
, err
= GetLastError() );
5056 SetEvent( gSMBThreadRegisterEvent
);
5058 m
->p
->smbFileSharing
= mDNStrue
;
5060 else if ( m
->p
->smbFileSharing
&& !fileSharing
)
5062 dlog( kDebugLevelTrace
, DEBUG_NAME
"deregistering smb type\n" );
5064 if ( gSMBThreadDeregisterEvent
!= NULL
)
5066 SetEvent( gSMBThreadDeregisterEvent
);
5069 m
->p
->smbFileSharing
= mDNSfalse
;
5082 IsWOMPEnabled( mDNS
* const m
)
5086 mDNSInterfaceData
* ifd
;
5090 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
5092 if ( IsWOMPEnabledForAdapter( ifd
->name
) )
5104 IsWOMPEnabledForAdapter( const char * adapterName
)
5109 HANDLE handle
= INVALID_HANDLE_VALUE
;
5110 NDIS_PNP_CAPABILITIES
* pNPC
= NULL
;
5114 require_action( adapterName
!= NULL
, exit
, ok
= FALSE
);
5116 dlog( kDebugLevelTrace
, DEBUG_NAME
"IsWOMPEnabledForAdapter: %s\n", adapterName
);
5118 // Construct a device name to pass to CreateFile
5120 strncpy_s( fileName
, sizeof( fileName
), DEVICE_PREFIX
, strlen( DEVICE_PREFIX
) );
5121 strcat_s( fileName
, sizeof( fileName
), adapterName
);
5122 handle
= CreateFileA( fileName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, INVALID_HANDLE_VALUE
);
5123 require_action ( handle
!= INVALID_HANDLE_VALUE
, exit
, ok
= FALSE
);
5125 // We successfully opened the driver, format the IOCTL to pass the driver.
5127 oid
= OID_PNP_CAPABILITIES
;
5128 pNPC
= ( NDIS_PNP_CAPABILITIES
* ) malloc( sizeof( NDIS_PNP_CAPABILITIES
) );
5129 require_action( pNPC
!= NULL
, exit
, ok
= FALSE
);
5130 ok
= ( mDNSu8
) DeviceIoControl( handle
, IOCTL_NDIS_QUERY_GLOBAL_STATS
, &oid
, sizeof( oid
), pNPC
, sizeof( NDIS_PNP_CAPABILITIES
), &count
, NULL
);
5131 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
5132 require_action( !err
, exit
, ok
= FALSE
);
5133 ok
= ( mDNSu8
) ( ( count
== sizeof( NDIS_PNP_CAPABILITIES
) ) && ( pNPC
->Flags
& NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE
) );
5142 if ( handle
!= INVALID_HANDLE_VALUE
)
5144 CloseHandle( handle
);
5147 dlog( kDebugLevelTrace
, DEBUG_NAME
"IsWOMPEnabledForAdapter returns %s\n", ok
? "true" : "false" );
5149 return ( mDNSu8
) ok
;
5154 SetSocketEventsEnabled( mDNS
* const inMDNS
, BOOL enabled
)
5156 DEBUG_UNUSED( inMDNS
);
5162 check( !gSocketEventsEnabled
);
5164 // If we're enabled, then drain the queue right now.
5166 while ( gSocketEvents
.Head
&& ( numEvents
< 100 ) )
5168 SocketEvent
* event
= ( SocketEvent
* ) gSocketEvents
.Head
;
5169 RemoveFromList( &gSocketEvents
, event
);
5170 check( event
->handler
);
5172 // At this point we're going to call our event handler, and
5173 // gSocketEventsEnabled should be FALSE. So if the callback
5174 // does anything that causes alertable I/O callbacks to be
5175 // invoked, we'll queue the packets instead of invoking core
5176 // callbacks reentrantly.
5178 // One potential problem here is a pathological case of
5179 // continuing to queue packets during invocation of
5180 // the callback, and thus never exiting out of this loop.
5181 // This is entirely theoretical as we've never seen it happen,
5182 // but just to be overly cautious, we'll only process a maximum of
5183 // 100 events here just in case.
5185 event
->handler( inMDNS
, event
);
5192 gSocketEventsEnabled
= enabled
;
5197 FreeSocketEventsForSocket( mDNS
* const inMDNS
, void * sock
)
5199 SocketEvent
* event
;
5201 DEBUG_UNUSED( inMDNS
);
5203 for ( event
= ( SocketEvent
* ) gSocketEvents
.Head
; event
; event
= event
->next
)
5205 if ( event
->sock
== sock
)
5207 RemoveFromList( &gSocketEvents
, event
);
5216 FreeSocketEvents( mDNS
* const inMDNS
)
5218 DEBUG_UNUSED( inMDNS
);
5220 while ( gSocketEvents
.Head
)
5222 SocketEvent
* event
= ( SocketEvent
* ) gSocketEvents
.Head
;
5223 RemoveFromList( &gSocketEvents
, event
);
5230 TCPSocketEventHandler( mDNS
* const inMDNS
, void * v
)
5232 TCPSocketEvent
* event
= ( TCPSocketEvent
* ) v
;
5233 TCPSocket
* sock
= ( TCPSocket
* ) event
->super
.sock
;
5235 DEBUG_UNUSED( inMDNS
);
5238 sock
->lastError
= event
->error
;
5240 if ( !event
->error
)
5242 if ( event
->bytesTransferred
)
5244 memcpy( sock
->buf
, event
->buf
, event
->bytesTransferred
);
5245 sock
->bptr
= sock
->buf
;
5246 sock
->eptr
= sock
->buf
+ event
->bytesTransferred
;
5250 sock
->closed
= TRUE
;
5254 if ( sock
->readEventHandler
!= NULL
)
5256 sock
->readEventHandler( sock
);
5262 UDPSocketEventHandler( mDNS
* const inMDNS
, void * v
)
5264 UDPSocketEvent
* event
= ( UDPSocketEvent
* ) v
;
5266 mDNSCoreReceive( inMDNS
, &event
->packet
, event
->end
, &event
->srcAddr
, event
->srcPort
, &event
->dstAddr
, event
->dstPort
, event
->iid
);