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.
17 Change History (most recent first):
20 Revision 1.128 2007/09/12 19:23:17 cheshire
21 Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
23 Revision 1.127 2007/07/20 00:54:22 cheshire
24 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
26 Revision 1.126 2007/07/11 02:56:20 cheshire
27 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
28 Remove unused mDNSPlatformDefaultRegDomainChanged
30 Revision 1.125 2007/06/20 01:10:13 cheshire
31 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
33 Revision 1.124 2007/04/26 00:35:16 cheshire
34 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
35 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
36 inside the firewall may give answers where a public one gives none, and vice versa.)
38 Revision 1.123 2007/04/18 21:00:40 cheshire
39 Use mDNS_AddSearchDomain_CString() instead of MakeDomainNameFromDNSNameString ... mDNS_AddSearchDomain
41 Revision 1.122 2007/04/17 19:21:29 cheshire
42 <rdar://problem/5140339> Domain discovery not working over VPN
44 Revision 1.121 2007/04/05 20:40:37 cheshire
45 Remove unused mDNSPlatformTCPGetFlags()
47 Revision 1.120 2007/03/28 20:59:27 cheshire
48 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
50 Revision 1.119 2007/03/28 15:56:38 cheshire
51 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
53 Revision 1.118 2007/03/22 18:31:49 cheshire
54 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
56 Revision 1.117 2007/03/21 00:30:07 cheshire
57 <rdar://problem/4789455> Multiple errors in DNameList-related code
59 Revision 1.116 2007/03/20 17:07:16 cheshire
60 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
62 Revision 1.115 2007/02/08 21:12:28 cheshire
63 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
65 Revision 1.114 2007/01/05 08:31:01 cheshire
66 Trim excessive "$Log" checkin history from before 2006
67 (checkin history still available via "cvs log ..." of course)
69 Revision 1.113 2007/01/04 23:12:20 cheshire
70 Remove unused mDNSPlatformDefaultBrowseDomainChanged
72 Revision 1.112 2006/12/22 20:59:51 cheshire
73 <rdar://problem/4742742> Read *all* DNS keys from keychain,
74 not just key for the system-wide default registration domain
76 Revision 1.111 2006/12/19 22:43:56 cheshire
79 Revision 1.110 2006/09/27 00:47:40 herscher
80 Fix compile error caused by changes to the tcp callback api.
82 Revision 1.109 2006/08/14 23:25:21 cheshire
83 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
85 Revision 1.108 2006/07/06 00:06:21 cheshire
86 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
88 Revision 1.107 2006/03/19 02:00:13 cheshire
89 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
91 Revision 1.106 2006/02/26 19:31:05 herscher
92 <rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency. The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it. 2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
96 - Get unicode name of machine for nice name instead of just the host name.
97 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
98 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
99 - Implement TCP support for truncated packets (only stubs now).
109 #include "CommonServices.h"
110 #include "DebugServices.h"
111 #include "VPCDetect.h"
112 #include "RegNames.h"
115 #include <Iphlpapi.h>
116 #if( !TARGET_OS_WINDOWS_CE )
119 #include <ntsecapi.h>
122 #include "mDNSEmbeddedAPI.h"
124 #include "mDNSWin32.h"
127 #pragma mark == Constants ==
130 //===========================================================================================================================
132 //===========================================================================================================================
134 #define DEBUG_NAME "[mDNSWin32] "
136 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
137 #define MDNS_WINDOWS_ENABLE_IPV4 1
138 #define MDNS_WINDOWS_ENABLE_IPV6 1
139 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
140 #define MDNS_SET_HINFO_STRINGS 0
142 #define kMDNSDefaultName "My Computer"
144 #define kWinSockMajorMin 2
145 #define kWinSockMinorMin 2
147 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
148 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
149 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
150 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
151 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
152 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
153 #define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
155 #define kRegistryMaxKeyLength 255
157 #if( !TARGET_OS_WINDOWS_CE )
158 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
161 #define kIPv6IfIndexBase (10000000L)
163 #define kRetryVPCRate (-100000000)
164 #define kRetryVPCMax (10)
168 #pragma mark == Prototypes ==
171 //===========================================================================================================================
173 //===========================================================================================================================
175 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
176 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
177 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
178 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
179 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
180 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
181 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
182 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
183 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
184 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
185 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
186 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
187 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
188 mDNSlocal mStatus
SetupRetryVPCCheck( mDNS
* const inMDNS
);
189 mDNSlocal mStatus
TearDownRetryVPCCheck( mDNS
* const inMDNS
);
191 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
192 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
193 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
194 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
195 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
196 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
);
197 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
198 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
* inMDNS
);
199 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
);
200 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
* inMDNS
);
201 mDNSlocal
void ProcessingThreadRetryVPCCheck( mDNS
* inMDNS
);
204 // Platform Accessors
210 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
211 struct mDNSPlatformInterfaceInfo
217 struct TCPSocket_struct
220 TCPSocketFlags flags
;
222 TCPConnectionCallback callback
;
229 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
230 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
234 typedef struct PolyString PolyString
;
240 PLSA_UNICODE_STRING m_lsa
;
244 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
245 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
248 #if( !TARGET_OS_WINDOWS_CE )
249 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
252 #if( TARGET_OS_WINDOWS_CE )
253 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
256 mDNSlocal DWORD
GetPrimaryInterface();
257 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
258 mDNSlocal mDNSBool
CanReceiveUnicast( void );
259 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
261 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
262 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
263 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
264 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
265 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
266 mDNSlocal OSStatus
MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
);
267 mDNSlocal OSStatus
MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
);
268 mDNSlocal
void FreeTCPSocket( TCPSocket
*sock
);
269 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
);
276 #pragma mark == Globals ==
279 //===========================================================================================================================
281 //===========================================================================================================================
283 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
284 mDNSs32 mDNSPlatformOneSecond
= 0;
285 mDNSlocal TCPSocket
* gTCPConnectionList
= NULL
;
286 mDNSlocal
int gTCPConnections
= 0;
287 mDNSlocal BOOL gWaitListChanged
= FALSE
;
289 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
292 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
296 PIP_ADAPTER_ADDRESSES inAdapter
,
297 PULONG outBufferSize
);
299 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
300 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
306 #pragma mark == Platform Support ==
309 //===========================================================================================================================
311 //===========================================================================================================================
313 mDNSexport mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
318 struct sockaddr_in sa4
;
319 struct sockaddr_in6 sa6
;
323 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
325 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
326 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
328 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
329 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
330 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
331 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
333 // Startup WinSock 2.2 or later.
335 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
336 require_noerr( err
, exit
);
338 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
339 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
341 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
343 // Setup the HINFO HW/SW strings.
345 #if ( MDNS_SET_HINFO_STRINGS )
346 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
348 // Note that GetWindowsVersionString guarantees that the resulting string is always null-terminated,
349 // so the following strlen call is safe
350 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
351 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
353 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
354 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
355 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
356 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
361 inMDNS
->p
->vpcCheckCount
= 0;
362 inMDNS
->p
->vpcCheckEvent
= NULL
;
363 inMDNS
->p
->timersCount
= 0;
365 // Set up the IPv4 unicast socket
367 inMDNS
->p
->unicastSock4
= INVALID_SOCKET
;
368 inMDNS
->p
->unicastSock4ReadEvent
= NULL
;
369 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
371 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
373 sa4
.sin_family
= AF_INET
;
374 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
375 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
);
377 sa4len
= sizeof( sa4
);
378 err
= getsockname( inMDNS
->p
->unicastSock4
, (struct sockaddr
*) &sa4
, &sa4len
);
379 require_noerr( err
, exit
);
380 inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
381 inMDNS
->p
->unicastSock4ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
382 err
= translate_errno( inMDNS
->p
->unicastSock4ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
383 require_noerr( err
, exit
);
384 err
= WSAEventSelect( inMDNS
->p
->unicastSock4
, inMDNS
->p
->unicastSock4ReadEvent
, FD_READ
);
385 require_noerr( err
, exit
);
386 #if( !TARGET_OS_WINDOWS_CE )
390 err
= WSAIoctl( inMDNS
->p
->unicastSock4
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
391 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock4RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock4RecvMsgPtr
), &size
, NULL
, NULL
);
395 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
402 // Set up the IPv6 unicast socket
404 inMDNS
->p
->unicastSock6
= INVALID_SOCKET
;
405 inMDNS
->p
->unicastSock6ReadEvent
= NULL
;
406 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
408 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
410 sa6
.sin6_family
= AF_INET6
;
411 sa6
.sin6_addr
= in6addr_any
;
412 sa6
.sin6_scope_id
= 0;
414 // This call will fail if the machine hasn't installed IPv6. In that case,
415 // the error will be WSAEAFNOSUPPORT.
417 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
);
418 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
419 inMDNS
->p
->unicastSock6ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
420 err
= translate_errno( inMDNS
->p
->unicastSock6ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
421 require_noerr( err
, exit
);
423 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
425 if ( inMDNS
->p
->unicastSock6
!= INVALID_SOCKET
)
427 sa6len
= sizeof( sa6
);
428 err
= getsockname( inMDNS
->p
->unicastSock6
, (struct sockaddr
*) &sa6
, &sa6len
);
429 require_noerr( err
, exit
);
430 inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
432 err
= WSAEventSelect( inMDNS
->p
->unicastSock6
, inMDNS
->p
->unicastSock6ReadEvent
, FD_READ
);
433 require_noerr( err
, exit
);
435 #if( !TARGET_OS_WINDOWS_CE )
439 err
= WSAIoctl( inMDNS
->p
->unicastSock6
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
440 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock6RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock6RecvMsgPtr
), &size
, NULL
, NULL
);
444 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
452 // Set up the mDNS thread.
454 err
= SetupSynchronizationObjects( inMDNS
);
455 require_noerr( err
, exit
);
457 err
= SetupThread( inMDNS
);
458 require_noerr( err
, exit
);
462 mDNSCoreInitComplete( inMDNS
, err
);
467 mDNSPlatformClose( inMDNS
);
469 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
473 //===========================================================================================================================
475 //===========================================================================================================================
477 mDNSexport
void mDNSPlatformClose( mDNS
* const inMDNS
)
481 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
484 // Tear everything down in reverse order to how it was set up.
486 err
= TearDownThread( inMDNS
);
489 err
= TearDownInterfaceList( inMDNS
);
491 check( !inMDNS
->p
->inactiveInterfaceList
);
493 err
= TearDownRetryVPCCheck( inMDNS
);
496 err
= TearDownSynchronizationObjects( inMDNS
);
499 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
501 if ( inMDNS
->p
->unicastSock4ReadEvent
)
503 CloseHandle( inMDNS
->p
->unicastSock4ReadEvent
);
504 inMDNS
->p
->unicastSock4ReadEvent
= 0;
507 if ( IsValidSocket( inMDNS
->p
->unicastSock4
) )
509 close_compat( inMDNS
->p
->unicastSock4
);
514 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
516 if ( inMDNS
->p
->unicastSock6ReadEvent
)
518 CloseHandle( inMDNS
->p
->unicastSock6ReadEvent
);
519 inMDNS
->p
->unicastSock6ReadEvent
= 0;
522 if ( IsValidSocket( inMDNS
->p
->unicastSock6
) )
524 close_compat( inMDNS
->p
->unicastSock6
);
529 // Free the DLL needed for IPv6 support.
531 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
532 if( gIPHelperLibraryInstance
)
534 gGetAdaptersAddressesFunctionPtr
= NULL
;
536 FreeLibrary( gIPHelperLibraryInstance
);
537 gIPHelperLibraryInstance
= NULL
;
543 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
546 //===========================================================================================================================
547 // mDNSPlatformSendUDP
548 //===========================================================================================================================
552 const mDNS
* const inMDNS
,
553 const void * const inMsg
,
554 const mDNSu8
* const inMsgEnd
,
555 mDNSInterfaceID inInterfaceID
,
556 const mDNSAddr
* inDstIP
,
557 mDNSIPPort inDstPort
)
559 SOCKET sendingsocket
= INVALID_SOCKET
;
560 mStatus err
= mStatus_NoError
;
561 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
562 struct sockaddr_storage addr
;
565 DEBUG_USE_ONLY( inMDNS
);
567 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
573 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
575 if( inDstIP
->type
== mDNSAddrType_IPv4
)
577 struct sockaddr_in
* sa4
;
579 sa4
= (struct sockaddr_in
*) &addr
;
580 sa4
->sin_family
= AF_INET
;
581 sa4
->sin_port
= inDstPort
.NotAnInteger
;
582 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
583 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock4
;
585 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
587 struct sockaddr_in6
* sa6
;
589 sa6
= (struct sockaddr_in6
*) &addr
;
590 sa6
->sin6_family
= AF_INET6
;
591 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
592 sa6
->sin6_flowinfo
= 0;
593 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
594 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
595 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock6
;
599 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
600 err
= mStatus_BadParamErr
;
604 if (IsValidSocket(sendingsocket
))
606 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
607 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
611 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
613 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
615 err
= mStatus_TransientErr
;
619 require_noerr( err
, exit
);
628 //===========================================================================================================================
630 //===========================================================================================================================
632 mDNSexport
void mDNSPlatformLock( const mDNS
* const inMDNS
)
636 if ( inMDNS
->p
->lockInitialized
)
638 EnterCriticalSection( &inMDNS
->p
->lock
);
642 //===========================================================================================================================
643 // mDNSPlatformUnlock
644 //===========================================================================================================================
646 mDNSexport
void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
651 if ( inMDNS
->p
->lockInitialized
)
653 check( inMDNS
->p
->threadID
);
655 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
656 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
658 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
662 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
663 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
665 LeaveCriticalSection( &inMDNS
->p
->lock
);
669 //===========================================================================================================================
670 // mDNSPlatformStrCopy
671 //===========================================================================================================================
673 mDNSexport
void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
678 strcpy( (char *) inDst
, (const char*) inSrc
);
681 //===========================================================================================================================
682 // mDNSPlatformStrLen
683 //===========================================================================================================================
685 mDNSexport mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
689 return( (mDNSu32
) strlen( (const char *) inSrc
) );
692 //===========================================================================================================================
693 // mDNSPlatformMemCopy
694 //===========================================================================================================================
696 mDNSexport
void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
701 memcpy( inDst
, inSrc
, inSize
);
704 //===========================================================================================================================
705 // mDNSPlatformMemSame
706 //===========================================================================================================================
708 mDNSexport mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
713 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
716 //===========================================================================================================================
717 // mDNSPlatformMemZero
718 //===========================================================================================================================
720 mDNSexport
void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
724 memset( inDst
, 0, inSize
);
727 //===========================================================================================================================
728 // mDNSPlatformMemAllocate
729 //===========================================================================================================================
731 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
737 mem
= malloc( inSize
);
743 //===========================================================================================================================
744 // mDNSPlatformMemFree
745 //===========================================================================================================================
747 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
754 //===========================================================================================================================
755 // mDNSPlatformRandomSeed
756 //===========================================================================================================================
758 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
760 return( GetTickCount() );
763 //===========================================================================================================================
764 // mDNSPlatformTimeInit
765 //===========================================================================================================================
767 mDNSexport mStatus
mDNSPlatformTimeInit( void )
769 // No special setup is required on Windows -- we just use GetTickCount().
770 return( mStatus_NoError
);
773 //===========================================================================================================================
774 // mDNSPlatformRawTime
775 //===========================================================================================================================
777 mDNSexport mDNSs32
mDNSPlatformRawTime( void )
779 return( (mDNSs32
) GetTickCount() );
782 //===========================================================================================================================
784 //===========================================================================================================================
786 mDNSexport mDNSs32
mDNSPlatformUTC( void )
788 return ( mDNSs32
) time( NULL
);
791 //===========================================================================================================================
792 // mDNSPlatformInterfaceNameToID
793 //===========================================================================================================================
795 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
798 mDNSInterfaceData
* ifd
;
804 // Search for an interface with the specified name,
806 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
808 if( strcmp( ifd
->name
, inName
) == 0 )
813 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
819 *outID
= (mDNSInterfaceID
) ifd
;
821 err
= mStatus_NoError
;
827 //===========================================================================================================================
828 // mDNSPlatformInterfaceIDToInfo
829 //===========================================================================================================================
831 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
834 mDNSInterfaceData
* ifd
;
840 // Search for an interface with the specified ID,
842 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
844 if( ifd
== (mDNSInterfaceData
*) inID
)
849 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
853 outInfo
->name
= ifd
->name
;
854 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
855 err
= mStatus_NoError
;
861 //===========================================================================================================================
862 // mDNSPlatformInterfaceIDfromInterfaceIndex
863 //===========================================================================================================================
865 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
* const inMDNS
, mDNSu32 inIndex
)
870 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
872 id
= mDNSInterface_LocalOnly
;
874 else if( inIndex
!= 0 )
876 mDNSInterfaceData
* ifd
;
878 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
880 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
882 id
= ifd
->interfaceInfo
.InterfaceID
;
891 //===========================================================================================================================
892 // mDNSPlatformInterfaceIndexfromInterfaceID
893 //===========================================================================================================================
895 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
* const inMDNS
, mDNSInterfaceID inID
)
900 if( inID
== mDNSInterface_LocalOnly
)
902 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
906 mDNSInterfaceData
* ifd
;
908 // Search active interfaces.
909 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
911 if( (mDNSInterfaceID
) ifd
== inID
)
913 index
= ifd
->scopeID
;
918 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
922 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
924 if( (mDNSInterfaceID
) ifd
== inID
)
926 index
= ifd
->scopeID
;
936 //===========================================================================================================================
937 // mDNSPlatformTCPSocket
938 //===========================================================================================================================
941 mDNSPlatformTCPSocket
944 TCPSocketFlags flags
,
948 TCPSocket
* sock
= NULL
;
949 u_long on
= 1; // "on" for setsockopt
950 struct sockaddr_in saddr
;
952 mStatus err
= mStatus_NoError
;
956 require_action( flags
== 0, exit
, err
= mStatus_UnsupportedErr
);
958 // Setup connection data object
960 sock
= (TCPSocket
*) malloc( sizeof( TCPSocket
) );
961 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
962 memset( sock
, 0, sizeof( TCPSocket
) );
964 sock
->fd
= INVALID_SOCKET
;
967 bzero(&saddr
, sizeof(saddr
));
968 saddr
.sin_family
= AF_INET
;
969 saddr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
970 saddr
.sin_port
= port
->NotAnInteger
;
974 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
975 err
= translate_errno( sock
->fd
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
976 require_noerr( err
, exit
);
978 // Set it to be non-blocking
980 err
= ioctlsocket( sock
->fd
, FIONBIO
, &on
);
981 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
982 require_noerr( err
, exit
);
986 memset( &saddr
, 0, sizeof( saddr
) );
987 len
= sizeof( saddr
);
989 err
= getsockname( sock
->fd
, ( struct sockaddr
* ) &saddr
, &len
);
990 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
991 require_noerr( err
, exit
);
993 port
->NotAnInteger
= saddr
.sin_port
;
999 FreeTCPSocket( sock
);
1006 //===========================================================================================================================
1007 // mDNSPlatformTCPConnect
1008 //===========================================================================================================================
1011 mDNSPlatformTCPConnect
1014 const mDNSAddr
* inDstIP
,
1015 mDNSOpaque16 inDstPort
,
1016 mDNSInterfaceID inInterfaceID
,
1017 TCPConnectionCallback inCallback
,
1021 struct sockaddr_in saddr
;
1022 mStatus err
= mStatus_NoError
;
1024 DEBUG_UNUSED( inInterfaceID
);
1026 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1028 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1029 return mStatus_UnknownErr
;
1032 // Setup connection data object
1034 sock
->callback
= inCallback
;
1035 sock
->context
= inContext
;
1037 bzero(&saddr
, sizeof(saddr
));
1038 saddr
.sin_family
= AF_INET
;
1039 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1040 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1042 // Try and do connect
1044 err
= connect( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1045 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1046 sock
->connected
= !err
? TRUE
: FALSE
;
1047 sock
->pendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1048 err
= translate_errno( sock
->pendingEvent
, GetLastError(), mStatus_UnknownErr
);
1049 require_noerr( err
, exit
);
1050 err
= WSAEventSelect( sock
->fd
, sock
->pendingEvent
, FD_CONNECT
|FD_READ
|FD_CLOSE
);
1051 require_noerr( err
, exit
);
1055 sock
->next
= gTCPConnectionList
;
1056 gTCPConnectionList
= sock
;
1058 gWaitListChanged
= TRUE
;
1064 err
= sock
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1070 //===========================================================================================================================
1071 // mDNSPlatformTCPAccept
1072 //===========================================================================================================================
1075 mDNSexport TCPSocket
*mDNSPlatformTCPAccept( TCPSocketFlags flags
, int fd
)
1077 TCPSocket
* sock
= NULL
;
1078 mStatus err
= mStatus_NoError
;
1080 require_action( !flags
, exit
, err
= mStatus_UnsupportedErr
);
1082 sock
= malloc( sizeof( TCPSocket
) );
1083 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1085 memset( sock
, 0, sizeof( *sock
) );
1088 sock
->flags
= flags
;
1102 //===========================================================================================================================
1103 // mDNSPlatformTCPCloseConnection
1104 //===========================================================================================================================
1106 mDNSexport
void mDNSPlatformTCPCloseConnection( TCPSocket
*sock
)
1108 TCPSocket
* inserted
= gTCPConnectionList
;
1109 TCPSocket
* last
= NULL
;
1113 if ( inserted
== sock
)
1117 gTCPConnectionList
= inserted
->next
;
1121 last
->next
= inserted
->next
;
1125 gWaitListChanged
= TRUE
;
1131 inserted
= inserted
->next
;
1134 FreeTCPSocket( sock
);
1137 //===========================================================================================================================
1138 // mDNSPlatformReadTCP
1139 //===========================================================================================================================
1141 mDNSexport
long mDNSPlatformReadTCP( TCPSocket
*sock
, void *inBuffer
, unsigned long inBufferSize
, mDNSBool
* closed
)
1145 nread
= recv( sock
->fd
, inBuffer
, inBufferSize
, 0);
1149 if ( WSAGetLastError() == WSAEWOULDBLOCK
)
1166 //===========================================================================================================================
1167 // mDNSPlatformWriteTCP
1168 //===========================================================================================================================
1170 mDNSexport
long mDNSPlatformWriteTCP( TCPSocket
*sock
, const char *inMsg
, unsigned long inMsgSize
)
1175 nsent
= send( sock
->fd
, inMsg
, inMsgSize
, 0 );
1177 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1178 require_noerr( err
, exit
);
1190 //===========================================================================================================================
1191 // mDNSPlatformTCPGetFD
1192 //===========================================================================================================================
1194 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1196 return ( int ) sock
->fd
;
1199 //===========================================================================================================================
1200 // mDNSPlatformUDPSocket
1201 //===========================================================================================================================
1203 mDNSexport UDPSocket
*mDNSPlatformUDPSocket
1210 DEBUG_UNUSED( port
);
1215 //===========================================================================================================================
1216 // mDNSPlatformUDPClose
1217 //===========================================================================================================================
1219 mDNSexport
void mDNSPlatformUDPClose( UDPSocket
*sock
)
1221 DEBUG_UNUSED( sock
);
1225 //===========================================================================================================================
1226 // mDNSPlatformTLSSetupCerts
1227 //===========================================================================================================================
1230 mDNSPlatformTLSSetupCerts(void)
1232 return mStatus_UnsupportedErr
;
1235 //===========================================================================================================================
1236 // mDNSPlatformTLSTearDownCerts
1237 //===========================================================================================================================
1240 mDNSPlatformTLSTearDownCerts(void)
1244 //===========================================================================================================================
1245 // mDNSPlatformSetDNSConfig
1246 //===========================================================================================================================
1248 mDNSlocal
void SetDNSServers( mDNS
*const m
);
1249 mDNSlocal
void SetSearchDomainList( void );
1252 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**browseDomains
)
1255 char subKeyName
[kRegistryMaxKeyLength
+ 1];
1267 if (setservers
) SetDNSServers(m
);
1268 if (setsearch
) SetSearchDomainList();
1274 *browseDomains
= NULL
;
1276 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
1277 require_noerr( err
, exit
);
1279 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1280 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1282 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
1284 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
1300 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
, &key
);
1301 require_noerr( err
, exit
);
1303 // Get information about this node
1305 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
1306 require_noerr( err
, exit
);
1308 for ( i
= 0; i
< cSubKeys
; i
++)
1312 dwSize
= kRegistryMaxKeyLength
;
1314 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1318 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
1319 require_noerr( err
, exit
);
1321 dwSize
= sizeof( DWORD
);
1322 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
1324 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
1326 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
1328 dlog( kDebugLevelError
, "bad DDNS browse domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
1332 DNameListElem
* browseDomain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1333 require_action( browseDomain
, exit
, err
= mStatus_NoMemoryErr
);
1335 AssignDomainName(&browseDomain
->name
, &dname
);
1336 browseDomain
->next
= *browseDomains
;
1338 *browseDomains
= browseDomain
;
1342 RegCloseKey( subKey
);
1353 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
, &key
);
1354 require_noerr( err
, exit
);
1356 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1357 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1359 *RegDomains
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1360 if (!*RegDomains
) dlog( kDebugLevelError
, "No memory");
1363 (*RegDomains
)->next
= mDNSNULL
;
1364 if ( !MakeDomainNameFromDNSNameString( &(*RegDomains
)->name
, name
) || (*RegDomains
)->name
.c
[0] )
1366 dlog( kDebugLevelError
, "bad DDNS registration domain in registry: %s", name
[0] ? name
: "(unknown)");
1375 RegCloseKey( subKey
);
1390 //===========================================================================================================================
1391 // mDNSPlatformDynDNSHostNameStatusChanged
1392 //===========================================================================================================================
1395 mDNSPlatformDynDNSHostNameStatusChanged(domainname
*const dname
, mStatus status
)
1397 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1403 ConvertDomainNameToCString(dname
, uname
);
1409 *p
= (char) tolower(*p
);
1410 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1414 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1415 name
= kServiceParametersNode
TEXT("\\DynDNS\\State\\HostNames");
1416 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1417 require_noerr( err
, exit
);
1419 status
= ( status
) ? 0 : 1;
1420 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &status
, sizeof(DWORD
) );
1421 require_noerr( err
, exit
);
1434 //===========================================================================================================================
1436 //===========================================================================================================================
1438 // This routine needs to be called whenever the system secrets database changes.
1439 // Right now I call it from ProcessingThreadDynDNSConfigChanged, which may or may not be sufficient.
1440 // Also, it needs to call mDNS_SetSecretForDomain() for *every* configured DNS domain/secret pair
1441 // in the database, not just inDomain (the inDomain parameter should be deleted).
1444 SetDomainSecrets( mDNS
* const m
, const domainname
* inDomain
)
1451 LSA_OBJECT_ATTRIBUTES attrs
;
1452 LSA_HANDLE handle
= NULL
;
1456 // Initialize PolyStrings
1458 domain
.m_lsa
= NULL
;
1460 secret
.m_lsa
= NULL
;
1462 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
1464 ConvertDomainNameToCString( inDomain
, domain
.m_utf8
);
1465 dlen
= strlen( domain
.m_utf8
);
1466 for ( i
= 0; i
< dlen
; i
++ )
1468 domain
.m_utf8
[i
] = (char) tolower( domain
.m_utf8
[i
] ); // canonicalize -> lower case
1471 MakeDomainNameFromDNSNameString( &domain
.m_dname
, domain
.m_utf8
);
1473 // attrs are reserved, so initialize to zeroes.
1475 ZeroMemory( &attrs
, sizeof( attrs
) );
1477 // Get a handle to the Policy object on the local system
1479 res
= LsaOpenPolicy( NULL
, &attrs
, POLICY_GET_PRIVATE_INFORMATION
, &handle
);
1480 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1481 require_noerr( err
, exit
);
1483 // Get the encrypted data
1485 domain
.m_lsa
= ( PLSA_UNICODE_STRING
) malloc( sizeof( LSA_UNICODE_STRING
) );
1486 require_action( domain
.m_lsa
!= NULL
, exit
, err
= mStatus_NoMemoryErr
);
1487 err
= MakeLsaStringFromUTF8String( domain
.m_lsa
, domain
.m_utf8
);
1488 require_noerr( err
, exit
);
1492 res
= LsaRetrievePrivateData( handle
, domain
.m_lsa
, &key
.m_lsa
);
1493 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1494 require_noerr_quiet( err
, exit
);
1496 // <rdar://problem/4192119> Lsa secrets use a flat naming space. Therefore, we will prepend "$" to the keyname to
1497 // make sure it doesn't conflict with a zone name.
1499 // Convert the key to a domainname. Strip off the "$" prefix.
1501 err
= MakeUTF8StringFromLsaString( key
.m_utf8
, sizeof( key
.m_utf8
), key
.m_lsa
);
1502 require_noerr( err
, exit
);
1503 require_action( key
.m_utf8
[0] == '$', exit
, err
= kUnknownErr
);
1504 MakeDomainNameFromDNSNameString( &key
.m_dname
, key
.m_utf8
+ 1 );
1506 // Retrieve the secret
1508 res
= LsaRetrievePrivateData( handle
, key
.m_lsa
, &secret
.m_lsa
);
1509 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1510 require_noerr_quiet( err
, exit
);
1512 // Convert the secret to UTF8 string
1514 err
= MakeUTF8StringFromLsaString( secret
.m_utf8
, sizeof( secret
.m_utf8
), secret
.m_lsa
);
1515 require_noerr( err
, exit
);
1517 // And finally, tell the core about this secret
1519 debugf("Setting shared secret for zone %s with key %##s", domain
.m_utf8
, key
.m_dname
.c
);
1520 mDNS_SetSecretForDomain( m
, &domain
.m_dname
, &key
.m_dname
, secret
.m_utf8
, mDNSfalse
);
1524 if ( domain
.m_lsa
!= NULL
)
1526 if ( domain
.m_lsa
->Buffer
!= NULL
)
1528 free( domain
.m_lsa
->Buffer
);
1531 free( domain
.m_lsa
);
1534 if ( key
.m_lsa
!= NULL
)
1536 LsaFreeMemory( key
.m_lsa
);
1539 if ( secret
.m_lsa
!= NULL
)
1541 LsaFreeMemory( secret
.m_lsa
);
1552 //===========================================================================================================================
1553 // SetSearchDomainList
1554 //===========================================================================================================================
1556 mDNSlocal
void SetDomainFromDHCP( void );
1557 mDNSlocal
void SetReverseMapSearchDomainList( void );
1560 SetSearchDomainList( void )
1562 char * searchList
= NULL
;
1563 DWORD searchListLen
;
1564 DNameListElem
* head
= NULL
;
1565 DNameListElem
* current
= NULL
;
1570 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1571 require_noerr( err
, exit
);
1573 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1574 require_noerr( err
, exit
);
1576 // Windows separates the search domains with ','
1578 tok
= strtok( searchList
, "," );
1581 if ( ( strcmp( tok
, "" ) != 0 ) && ( strcmp( tok
, "." ) != 0 ) )
1582 mDNS_AddSearchDomain_CString(tok
);
1583 tok
= strtok( NULL
, "," );
1598 SetDomainFromDHCP();
1599 SetReverseMapSearchDomainList();
1603 //===========================================================================================================================
1604 // SetReverseMapSearchDomainList
1605 //===========================================================================================================================
1608 SetReverseMapSearchDomainList( void )
1610 struct ifaddrs
* ifa
;
1612 ifa
= myGetIfAddrs( 1 );
1617 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1622 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
1624 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1625 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1626 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1627 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1628 mDNS_AddSearchDomain_CString(buffer
);
1632 ifa
= ifa
->ifa_next
;
1639 //===========================================================================================================================
1641 //===========================================================================================================================
1644 SetDNSServers( mDNS
*const m
)
1646 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1647 FIXED_INFO
* fixedInfo
= NULL
;
1649 IP_ADDR_STRING
* dnsServerList
;
1650 IP_ADDR_STRING
* ipAddr
;
1653 mStatus err
= kUnknownErr
;
1655 // Get the primary interface.
1657 index
= GetPrimaryInterface();
1659 // This should have the interface index of the primary index. Fall back in cases where
1660 // it can't be determined.
1666 for ( i
= 0; i
< 100; i
++ )
1668 err
= GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
);
1670 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1675 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1676 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1679 require_noerr( err
, exit
);
1681 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1685 bufLen
= sizeof( FIXED_INFO
);
1687 for ( i
= 0; i
< 100; i
++ )
1691 GlobalFree( fixedInfo
);
1695 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1696 require_action( fixedInfo
, exit
, err
= mStatus_NoMemoryErr
);
1698 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1700 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1706 require_noerr( err
, exit
);
1708 dnsServerList
= &fixedInfo
->DnsServerList
;
1711 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1714 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1715 if ( !err
) mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, addr
, UnicastDNSPort
);
1722 free( pAdapterInfo
);
1727 GlobalFree( fixedInfo
);
1732 //===========================================================================================================================
1733 // SetDomainFromDHCP
1734 //===========================================================================================================================
1737 SetDomainFromDHCP( void )
1739 DNameListElem
* head
= NULL
;
1741 IP_ADAPTER_INFO
* pAdapterInfo
;
1742 IP_ADAPTER_INFO
* pAdapter
;
1746 LPSTR domain
= NULL
;
1749 mStatus err
= mStatus_NoError
;
1751 pAdapterInfo
= NULL
;
1753 for ( i
= 0; i
< 100; i
++ )
1755 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1757 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1762 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
1763 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1766 require_noerr( err
, exit
);
1768 index
= GetPrimaryInterface();
1770 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1772 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1773 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1774 pAdapter
->GatewayList
.IpAddress
.String
&&
1775 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1776 ( !index
|| ( pAdapter
->Index
== index
) ) )
1778 // Found one that will work
1782 _snprintf( keyName
, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter
->AdapterName
);
1784 err
= RegCreateKeyA( HKEY_LOCAL_MACHINE
, keyName
, &key
);
1785 require_noerr( err
, exit
);
1787 err
= RegQueryString( key
, "Domain", &domain
, &dwSize
, NULL
);
1790 if ( !domain
|| !domain
[0] )
1798 err
= RegQueryString( key
, "DhcpDomain", &domain
, &dwSize
, NULL
);
1802 if ( domain
&& domain
[0] ) mDNS_AddSearchDomain_CString(domain
);
1812 free( pAdapterInfo
);
1827 //===========================================================================================================================
1828 // mDNSPlatformGetPrimaryInterface
1829 //===========================================================================================================================
1832 mDNSPlatformGetPrimaryInterface( mDNS
* const m
, mDNSAddr
* v4
, mDNSAddr
* v6
, mDNSAddr
* router
)
1834 IP_ADAPTER_INFO
* pAdapterInfo
;
1835 IP_ADAPTER_INFO
* pAdapter
;
1840 mStatus err
= mStatus_NoError
;
1846 pAdapterInfo
= NULL
;
1850 for ( i
= 0; i
< 100; i
++ )
1852 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1854 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1859 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
1860 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1863 require_noerr( err
, exit
);
1865 index
= GetPrimaryInterface();
1867 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1869 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1870 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1871 pAdapter
->GatewayList
.IpAddress
.String
&&
1872 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1873 ( StringToAddress( v4
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
1874 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
1875 ( !index
|| ( pAdapter
->Index
== index
) ) )
1877 // Found one that will work
1888 free( pAdapterInfo
);
1899 //===========================================================================================================================
1901 //===========================================================================================================================
1903 #if( MDNS_DEBUGMSGS )
1904 mDNSexport
void debugf_( const char *inFormat
, ... )
1910 va_start( args
, inFormat
);
1911 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
1914 dlog( kDebugLevelInfo
, "%s\n", buffer
);
1918 //===========================================================================================================================
1920 //===========================================================================================================================
1922 #if( MDNS_DEBUGMSGS > 1 )
1923 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
1929 va_start( args
, inFormat
);
1930 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
1933 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
1937 //===========================================================================================================================
1939 //===========================================================================================================================
1942 mDNSexport void LogMsg( const char *inFormat, ... )
1948 va_start( args, inFormat );
1949 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
1952 dlog( kDebugLevelWarning, "%s\n", buffer );
1958 #pragma mark == Platform Internals ==
1961 //===========================================================================================================================
1962 // SetupSynchronizationObjects
1963 //===========================================================================================================================
1965 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
1969 InitializeCriticalSection( &inMDNS
->p
->lock
);
1970 inMDNS
->p
->lockInitialized
= mDNStrue
;
1972 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1973 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1974 require_noerr( err
, exit
);
1976 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1977 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1978 require_noerr( err
, exit
);
1980 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1981 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1982 require_noerr( err
, exit
);
1984 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1985 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1986 require_noerr( err
, exit
);
1991 TearDownSynchronizationObjects( inMDNS
);
1996 //===========================================================================================================================
1997 // TearDownSynchronizationObjects
1998 //===========================================================================================================================
2000 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
2002 if( inMDNS
->p
->quitEvent
)
2004 CloseHandle( inMDNS
->p
->quitEvent
);
2005 inMDNS
->p
->quitEvent
= 0;
2007 if( inMDNS
->p
->cancelEvent
)
2009 CloseHandle( inMDNS
->p
->cancelEvent
);
2010 inMDNS
->p
->cancelEvent
= 0;
2012 if( inMDNS
->p
->interfaceListChangedEvent
)
2014 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
2015 inMDNS
->p
->interfaceListChangedEvent
= 0;
2017 if( inMDNS
->p
->wakeupEvent
)
2019 CloseHandle( inMDNS
->p
->wakeupEvent
);
2020 inMDNS
->p
->wakeupEvent
= 0;
2022 if( inMDNS
->p
->lockInitialized
)
2024 DeleteCriticalSection( &inMDNS
->p
->lock
);
2025 inMDNS
->p
->lockInitialized
= mDNSfalse
;
2027 return( mStatus_NoError
);
2031 //===========================================================================================================================
2033 //===========================================================================================================================
2035 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
)
2038 char tempString
[ 256 ];
2043 // Set up the nice name.
2044 tempString
[ 0 ] = '\0';
2047 // First try and open the registry key that contains the computer description value
2048 if (inMDNS
->p
->descKey
== NULL
)
2050 LPCTSTR s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2051 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &inMDNS
->p
->descKey
);
2052 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2056 inMDNS
->p
->descKey
= NULL
;
2060 // if we opened it...
2061 if (inMDNS
->p
->descKey
!= NULL
)
2064 DWORD descSize
= sizeof( desc
);
2066 // look for the computer description
2067 err
= RegQueryValueEx(inMDNS
->p
->descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2071 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2080 // if we can't find it in the registry, then use the hostname of the machine
2081 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2083 DWORD tempStringLen
= sizeof( tempString
);
2086 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2087 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2092 err
= WindowsLatin1toUTF8( tempString
, utf8
, sizeof( utf8
) );
2101 // if we can't get the hostname
2102 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2104 // Invalidate name so fall back to a default name.
2106 strcpy( utf8
, kMDNSDefaultName
);
2109 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2110 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2111 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2113 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2119 //===========================================================================================================================
2121 //===========================================================================================================================
2123 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2126 char tempString
[ 256 ];
2127 DWORD tempStringLen
;
2128 domainlabel tempLabel
;
2133 // Set up the nice name.
2134 tempString
[ 0 ] = '\0';
2136 // use the hostname of the machine
2137 tempStringLen
= sizeof( tempString
);
2138 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2139 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2142 // if we can't get the hostname
2143 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2145 // Invalidate name so fall back to a default name.
2147 strcpy( tempString
, kMDNSDefaultName
);
2150 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2151 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2152 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2154 // Set up the host name.
2156 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2157 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2159 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2161 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2164 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2166 mDNS_SetFQDN( inMDNS
);
2168 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2173 //===========================================================================================================================
2175 //===========================================================================================================================
2177 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2183 err
= SetupNiceName( inMDNS
);
2186 err
= SetupHostName( inMDNS
);
2193 //===========================================================================================================================
2194 // SetupInterfaceList
2195 //===========================================================================================================================
2197 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2200 mDNSInterfaceData
** next
;
2201 mDNSInterfaceData
* ifd
;
2202 struct ifaddrs
* addrs
;
2204 struct ifaddrs
* loopbackv4
;
2205 struct ifaddrs
* loopbackv6
;
2210 mDNSBool foundUnicastSock4DestAddr
;
2211 mDNSBool foundUnicastSock6DestAddr
;
2213 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2217 inMDNS
->p
->registeredLoopback4
= mDNSfalse
;
2219 foundv4
= mDNSfalse
;
2220 foundv6
= mDNSfalse
;
2221 foundUnicastSock4DestAddr
= mDNSfalse
;
2222 foundUnicastSock6DestAddr
= mDNSfalse
;
2224 // Tear down any existing interfaces that may be set up.
2226 TearDownInterfaceList( inMDNS
);
2228 // Set up the name of this machine.
2230 err
= SetupName( inMDNS
);
2233 // Set up the interface list change notification.
2235 err
= SetupNotifications( inMDNS
);
2238 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2239 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2241 err
= getifaddrs( &addrs
);
2242 require_noerr( err
, exit
);
2246 next
= &inMDNS
->p
->interfaceList
;
2248 flagMask
= IFF_UP
| IFF_MULTICAST
;
2249 flagTest
= IFF_UP
| IFF_MULTICAST
;
2251 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2252 for( p
= addrs
; p
; p
= p
->ifa_next
)
2254 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2258 if( p
->ifa_flags
& IFF_LOOPBACK
)
2266 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2267 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2269 err
= SetupInterface( inMDNS
, p
, &ifd
);
2270 require_noerr( err
, exit
);
2272 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2273 // register him, but we also want to note that we haven't found a v4 interface
2274 // so that we register loopback so same host operations work
2276 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2281 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2282 // of determing the destination address of a packet that is sent to us.
2283 // For multicast packets, that's easy to determine. But for the unicast
2284 // sockets, we'll fake it by taking the address of the first interface
2285 // that is successfully setup.
2287 if ( !foundUnicastSock4DestAddr
)
2289 inMDNS
->p
->unicastSock4DestAddr
= ifd
->interfaceInfo
.ip
;
2290 foundUnicastSock4DestAddr
= TRUE
;
2295 ++inMDNS
->p
->interfaceCount
;
2299 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2301 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2302 for( p
= addrs
; p
; p
= p
->ifa_next
)
2304 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2308 if( p
->ifa_flags
& IFF_LOOPBACK
)
2316 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2317 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2319 err
= SetupInterface( inMDNS
, p
, &ifd
);
2320 require_noerr( err
, exit
);
2322 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2323 // register him, but we also want to note that we haven't found a v4 interface
2324 // so that we register loopback so same host operations work
2326 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2331 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2332 // of determing the destination address of a packet that is sent to us.
2333 // For multicast packets, that's easy to determine. But for the unicast
2334 // sockets, we'll fake it by taking the address of the first interface
2335 // that is successfully setup.
2337 if ( !foundUnicastSock6DestAddr
)
2339 inMDNS
->p
->unicastSock6DestAddr
= ifd
->interfaceInfo
.ip
;
2340 foundUnicastSock6DestAddr
= TRUE
;
2345 ++inMDNS
->p
->interfaceCount
;
2349 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2351 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2353 flagMask
|= IFF_LOOPBACK
;
2354 flagTest
|= IFF_LOOPBACK
;
2356 for( p
= addrs
; p
; p
= p
->ifa_next
)
2358 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2362 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2373 if ( !foundv4
&& loopbackv4
)
2375 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2376 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2378 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2379 require_noerr( err
, exit
);
2381 inMDNS
->p
->registeredLoopback4
= mDNStrue
;
2383 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2385 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2386 // of determing the destination address of a packet that is sent to us.
2387 // For multicast packets, that's easy to determine. But for the unicast
2388 // sockets, we'll fake it by taking the address of the first interface
2389 // that is successfully setup.
2391 if ( !foundUnicastSock4DestAddr
)
2393 inMDNS
->p
->unicastSock4DestAddr
= ifd
->defaultAddr
;
2394 foundUnicastSock4DestAddr
= TRUE
;
2400 ++inMDNS
->p
->interfaceCount
;
2406 TearDownInterfaceList( inMDNS
);
2410 freeifaddrs( addrs
);
2412 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2416 //===========================================================================================================================
2417 // TearDownInterfaceList
2418 //===========================================================================================================================
2420 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2423 mDNSInterfaceData
** p
;
2424 mDNSInterfaceData
* ifd
;
2426 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2430 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2431 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2432 // so that remove events that occur after an interface goes away can still report the correct interface.
2434 p
= &inMDNS
->p
->inactiveInterfaceList
;
2438 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2444 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2449 // Tear down interface list change notifications.
2451 err
= TearDownNotifications( inMDNS
);
2454 // Tear down all the interfaces.
2456 while( inMDNS
->p
->interfaceList
)
2458 ifd
= inMDNS
->p
->interfaceList
;
2459 inMDNS
->p
->interfaceList
= ifd
->next
;
2461 TearDownInterface( inMDNS
, ifd
);
2463 inMDNS
->p
->interfaceCount
= 0;
2465 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2466 return( mStatus_NoError
);
2469 //===========================================================================================================================
2471 //===========================================================================================================================
2473 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2475 mDNSInterfaceData
* ifd
;
2476 mDNSInterfaceData
* p
;
2481 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2485 check( inIFA
->ifa_addr
);
2488 // Allocate memory for the interface and initialize it.
2490 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2491 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2492 ifd
->sock
= kInvalidSocketRef
;
2493 ifd
->index
= inIFA
->ifa_extra
.index
;
2494 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2495 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2496 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2497 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2499 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2500 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2502 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2503 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2504 // on a large configured network, which means there's a good chance that most or all the other devices on that
2505 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2506 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2507 // devices on a large configured network, so we are willing to make that sacrifice.
2509 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2510 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2512 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2514 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2516 if (!ifd
->interfaceInfo
.InterfaceID
)
2518 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2521 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2522 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2523 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2525 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2532 if ( !ifd
->interfaceInfo
.InterfaceID
)
2534 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2537 // Set up a socket for this interface (if needed).
2539 if( ifd
->interfaceInfo
.McastTxRx
)
2541 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &sock
);
2542 require_noerr( err
, exit
);
2544 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2546 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2548 #if( !TARGET_OS_WINDOWS_CE )
2552 // If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
2553 // a bug in VPC itself.
2555 err
= inMDNS
->p
->inVirtualPC
;
2559 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
2560 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
2565 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
2570 // Set up the read pending event and associate it so we can block until data is available for this socket.
2572 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2573 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2574 require_noerr( err
, exit
);
2576 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
2577 require_noerr( err
, exit
);
2581 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2583 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2584 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2585 require_noerr( err
, exit
);
2588 // Register this interface with mDNS.
2590 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2591 require_noerr( err
, exit
);
2593 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2594 require_noerr( err
, exit
);
2596 ifd
->interfaceInfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
2598 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, mDNSfalse
);
2599 require_noerr( err
, exit
);
2600 ifd
->hostRegistered
= mDNStrue
;
2602 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2612 TearDownInterface( inMDNS
, ifd
);
2614 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2618 //===========================================================================================================================
2619 // TearDownInterface
2620 //===========================================================================================================================
2622 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2629 // Deregister this interface with mDNS.
2631 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2633 if( inIFD
->hostRegistered
)
2635 inIFD
->hostRegistered
= mDNSfalse
;
2636 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
, mDNSfalse
);
2639 // Tear down the multicast socket.
2641 if( inIFD
->readPendingEvent
)
2643 CloseHandle( inIFD
->readPendingEvent
);
2644 inIFD
->readPendingEvent
= 0;
2648 inIFD
->sock
= kInvalidSocketRef
;
2649 if( IsValidSocket( sock
) )
2651 close_compat( sock
);
2654 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2655 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2657 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2659 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2660 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2661 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2665 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2668 return( mStatus_NoError
);
2671 //===========================================================================================================================
2673 //===========================================================================================================================
2675 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2681 DEBUG_UNUSED( inMDNS
);
2683 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2685 check( outSocketRef
);
2687 // Set up an IPv4 or IPv6 UDP socket.
2689 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2690 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2691 require_noerr( err
, exit
);
2693 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2694 // if we're creating a multicast socket
2696 if ( port
.NotAnInteger
)
2699 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2700 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2703 if( inAddr
->sa_family
== AF_INET
)
2706 struct sockaddr_in sa4
;
2707 struct ip_mreq mreqv4
;
2709 // Bind the socket to the desired port
2711 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2712 memset( &sa4
, 0, sizeof( sa4
) );
2713 sa4
.sin_family
= AF_INET
;
2714 sa4
.sin_port
= port
.NotAnInteger
;
2715 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2717 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2718 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2720 // Turn on option to receive destination addresses and receiving interface.
2723 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2724 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2726 if (port
.NotAnInteger
)
2728 // Join the all-DNS multicast group so we receive Multicast DNS packets
2730 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
2731 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
2732 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
2733 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2735 // Specify the interface to send multicast packets on this socket.
2737 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2738 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
2739 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2741 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2744 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2745 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2748 // Send unicast packets with TTL 255 (helps against spoofing).
2751 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
2752 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2754 // Send multicast packets with TTL 255 (helps against spoofing).
2757 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
2758 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2761 else if( inAddr
->sa_family
== AF_INET6
)
2763 struct sockaddr_in6
* sa6p
;
2764 struct sockaddr_in6 sa6
;
2765 struct ipv6_mreq mreqv6
;
2767 sa6p
= (struct sockaddr_in6
*) inAddr
;
2769 // Bind the socket to the desired port
2771 memset( &sa6
, 0, sizeof( sa6
) );
2772 sa6
.sin6_family
= AF_INET6
;
2773 sa6
.sin6_port
= port
.NotAnInteger
;
2774 sa6
.sin6_flowinfo
= 0;
2775 sa6
.sin6_addr
= sa6p
->sin6_addr
;
2776 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
2778 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
2779 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2781 // Turn on option to receive destination addresses and receiving interface.
2784 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
2785 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2787 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
2788 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
2789 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
2791 #if( defined( IPV6_V6ONLY ) )
2793 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
2794 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2797 if ( port
.NotAnInteger
)
2799 // Join the all-DNS multicast group so we receive Multicast DNS packets.
2801 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroup_v6
.ip
.v6
);
2802 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
2803 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
2804 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2806 // Specify the interface to send multicast packets on this socket.
2808 option
= (int) sa6p
->sin6_scope_id
;
2809 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
2810 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2812 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2815 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2816 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2819 // Send unicast packets with TTL 255 (helps against spoofing).
2822 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
2823 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2825 // Send multicast packets with TTL 255 (helps against spoofing).
2828 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
2829 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2833 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
2834 err
= kUnsupportedErr
;
2840 *outSocketRef
= sock
;
2841 sock
= kInvalidSocketRef
;
2842 err
= mStatus_NoError
;
2845 if( IsValidSocket( sock
) )
2847 close_compat( sock
);
2852 //===========================================================================================================================
2854 //===========================================================================================================================
2856 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
2863 if( inSA
->sa_family
== AF_INET
)
2865 struct sockaddr_in
* sa4
;
2867 sa4
= (struct sockaddr_in
*) inSA
;
2868 outIP
->type
= mDNSAddrType_IPv4
;
2869 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
2872 outPort
->NotAnInteger
= sa4
->sin_port
;
2874 err
= mStatus_NoError
;
2876 else if( inSA
->sa_family
== AF_INET6
)
2878 struct sockaddr_in6
* sa6
;
2880 sa6
= (struct sockaddr_in6
*) inSA
;
2881 outIP
->type
= mDNSAddrType_IPv6
;
2882 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
2883 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
2885 outIP
->ip
.v6
.w
[ 1 ] = 0;
2889 outPort
->NotAnInteger
= sa6
->sin6_port
;
2891 err
= mStatus_NoError
;
2895 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
2896 err
= mStatus_BadParamErr
;
2901 //===========================================================================================================================
2902 // SetupNotifications
2903 //===========================================================================================================================
2905 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
2909 unsigned long param
;
2914 // Register to listen for address list changes.
2916 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2917 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2918 require_noerr( err
, exit
);
2919 inMDNS
->p
->interfaceListChangedSocket
= sock
;
2921 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
2922 // when a change to the interface list is detected.
2925 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
2926 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
2927 require_noerr( err
, exit
);
2931 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
2934 check( errno_compat() == WSAEWOULDBLOCK
);
2937 err
= WSAEventSelect( sock
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
2938 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
2939 require_noerr( err
, exit
);
2941 inMDNS
->p
->descChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
2942 err
= translate_errno( inMDNS
->p
->descChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2943 require_noerr( err
, exit
);
2945 if (inMDNS
->p
->descKey
!= NULL
)
2947 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
2948 require_noerr( err
, exit
);
2951 // This will catch all changes to tcp/ip networking, including changes to the domain search list
2953 inMDNS
->p
->tcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
2954 err
= translate_errno( inMDNS
->p
->tcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2955 require_noerr( err
, exit
);
2957 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS
->p
->tcpipKey
);
2958 require_noerr( err
, exit
);
2960 err
= RegNotifyChangeKeyValue(inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
2961 require_noerr( err
, exit
);
2963 // This will catch all changes to ddns configuration
2965 inMDNS
->p
->ddnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
2966 err
= translate_errno( inMDNS
->p
->ddnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2967 require_noerr( err
, exit
);
2969 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &inMDNS
->p
->ddnsKey
);
2970 require_noerr( err
, exit
);
2972 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
2973 require_noerr( err
, exit
);
2978 TearDownNotifications( inMDNS
);
2983 //===========================================================================================================================
2984 // TearDownNotifications
2985 //===========================================================================================================================
2987 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
2989 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
2991 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
2992 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
2995 if ( inMDNS
->p
->descChangedEvent
!= NULL
)
2997 CloseHandle( inMDNS
->p
->descChangedEvent
);
2998 inMDNS
->p
->descChangedEvent
= NULL
;
3001 if ( inMDNS
->p
->descKey
!= NULL
)
3003 RegCloseKey( inMDNS
->p
->descKey
);
3004 inMDNS
->p
->descKey
= NULL
;
3007 if ( inMDNS
->p
->tcpipChangedEvent
!= NULL
)
3009 CloseHandle( inMDNS
->p
->tcpipChangedEvent
);
3010 inMDNS
->p
->tcpipChangedEvent
= NULL
;
3013 if ( inMDNS
->p
->ddnsChangedEvent
!= NULL
)
3015 CloseHandle( inMDNS
->p
->ddnsChangedEvent
);
3016 inMDNS
->p
->ddnsChangedEvent
= NULL
;
3019 if ( inMDNS
->p
->ddnsKey
!= NULL
)
3021 RegCloseKey( inMDNS
->p
->ddnsKey
);
3022 inMDNS
->p
->ddnsKey
= NULL
;
3025 return( mStatus_NoError
);
3029 //===========================================================================================================================
3030 // SetupRetryVPCCheck
3031 //===========================================================================================================================
3034 SetupRetryVPCCheck( mDNS
* const inMDNS
)
3036 LARGE_INTEGER liDueTime
;
3040 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up retry VirtualPC check\n" );
3042 liDueTime
.QuadPart
= kRetryVPCRate
;
3044 // Create a waitable timer.
3046 inMDNS
->p
->vpcCheckEvent
= CreateWaitableTimer( NULL
, TRUE
, TEXT( "VPCCheckTimer" ) );
3047 err
= translate_errno( inMDNS
->p
->vpcCheckEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3048 require_noerr( err
, exit
);
3050 // Set a timer to wait for 10 seconds.
3052 ok
= SetWaitableTimer( inMDNS
->p
->vpcCheckEvent
, &liDueTime
, 0, NULL
, NULL
, 0 );
3053 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
3054 require_noerr( err
, exit
);
3056 inMDNS
->p
->timersCount
++;
3064 //===========================================================================================================================
3065 // TearDownRetryVPCCheck
3066 //===========================================================================================================================
3069 TearDownRetryVPCCheck( mDNS
* const inMDNS
)
3071 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down retry VirtualPC check\n" );
3073 if ( inMDNS
->p
->vpcCheckEvent
)
3075 CancelWaitableTimer( inMDNS
->p
->vpcCheckEvent
);
3076 CloseHandle( inMDNS
->p
->vpcCheckEvent
);
3078 inMDNS
->p
->vpcCheckEvent
= NULL
;
3079 inMDNS
->p
->timersCount
--;
3082 return ( mStatus_NoError
);
3090 //===========================================================================================================================
3092 //===========================================================================================================================
3094 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
3097 HANDLE threadHandle
;
3101 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
3103 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3104 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3106 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3107 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3108 require_noerr( err
, exit
);
3110 inMDNS
->p
->initStatus
= mStatus_Invalid
;
3112 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3113 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3115 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
3116 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
3117 require_noerr( err
, exit
);
3119 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
3120 err
= translate_errno( result
== WAIT_OBJECT_0
, (mStatus
) GetLastError(), kUnknownErr
);
3121 require_noerr( err
, exit
);
3122 err
= inMDNS
->p
->initStatus
;
3123 require_noerr( err
, exit
);
3126 if( inMDNS
->p
->initEvent
)
3128 CloseHandle( inMDNS
->p
->initEvent
);
3129 inMDNS
->p
->initEvent
= 0;
3131 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
3135 //===========================================================================================================================
3137 //===========================================================================================================================
3139 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
3141 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3142 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3144 if( inMDNS
->p
->cancelEvent
)
3149 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
3150 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3152 if( inMDNS
->p
->quitEvent
)
3154 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
3155 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
3158 return( mStatus_NoError
);
3161 //===========================================================================================================================
3163 //===========================================================================================================================
3165 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
3177 m
= (mDNS
*) inParam
;
3178 err
= ProcessingThreadInitialize( m
);
3184 // Set up the list of objects we'll be waiting on.
3188 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
3189 require_noerr( err
, exit
);
3191 // Main processing loop.
3193 gWaitListChanged
= FALSE
;
3197 // Give the mDNS core a chance to do its work and determine next event time.
3199 mDNSs32 interval
= mDNS_Execute(m
) - mDNS_TimeNow(m
);
3201 if ( gWaitListChanged
)
3206 if (m
->p
->idleThreadCallback
)
3208 interval
= m
->p
->idleThreadCallback(m
, interval
);
3210 if (interval
< 0) interval
= 0;
3211 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
3212 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
3214 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3216 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
3217 check( result
!= WAIT_FAILED
);
3219 if ( result
!= WAIT_FAILED
)
3221 if( result
== WAIT_TIMEOUT
)
3223 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3225 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
3228 else if( result
== kWaitListCancelEvent
)
3230 // Cancel event. Set the done flag and break to exit.
3232 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
3236 else if( result
== kWaitListInterfaceListChangedEvent
)
3238 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3240 ProcessingThreadInterfaceListChanged( m
);
3243 else if( result
== kWaitListWakeupEvent
)
3245 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3247 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
3250 else if ( result
== kWaitListComputerDescriptionEvent
)
3253 // The computer description might have changed
3255 ProcessingThreadComputerDescriptionChanged( m
);
3258 else if ( result
== kWaitListTCPIPEvent
)
3261 // The TCP/IP might have changed
3263 ProcessingThreadTCPIPConfigChanged( m
);
3266 else if ( result
== kWaitListDynDNSEvent
)
3269 // The DynDNS config might have changed
3271 ProcessingThreadDynDNSConfigChanged( m
);
3278 // Socket data available event. Determine which socket and process the packet.
3280 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
3281 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
3282 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
3283 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
3285 HANDLE signaledObject
;
3287 mDNSInterfaceData
* ifd
;
3290 signaledObject
= waitList
[ waitItemIndex
];
3292 if ( m
->p
->vpcCheckEvent
== signaledObject
)
3294 ProcessingThreadRetryVPCCheck( m
);
3299 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3300 if ( m
->p
->unicastSock4ReadEvent
== signaledObject
)
3302 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock4
);
3307 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3308 if ( m
->p
->unicastSock6ReadEvent
== signaledObject
)
3310 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock6
);
3315 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3317 if( ifd
->readPendingEvent
== signaledObject
)
3319 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
3324 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3326 if ( tcd
->pendingEvent
== signaledObject
)
3328 mDNSBool connect
= FALSE
;
3330 if ( !tcd
->connected
)
3332 tcd
->connected
= mDNStrue
;
3336 tcd
->callback( tcd
, tcd
->context
, connect
, 0 );
3348 // Unexpected wait result.
3350 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
3357 err
= ProcessingThreadInitialize( m
);
3363 // Release the wait list.
3373 // Signal the quit event to indicate that the thread is finished.
3376 wasSet
= SetEvent( m
->p
->quitEvent
);
3377 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3379 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3380 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3382 _endthreadex_compat( 0 );
3386 //===========================================================================================================================
3387 // ProcessingThreadInitialize
3388 //===========================================================================================================================
3390 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
3395 inMDNS
->p
->threadID
= GetCurrentThreadId();
3397 err
= IsVPCRunning( &inMDNS
->p
->inVirtualPC
);
3401 TearDownRetryVPCCheck( inMDNS
);
3402 SetupRetryVPCCheck( inMDNS
);
3405 err
= SetupInterfaceList( inMDNS
);
3406 require_noerr( err
, exit
);
3408 err
= uDNS_SetupDNSConfig( inMDNS
);
3409 require_noerr( err
, exit
);
3415 TearDownInterfaceList( inMDNS
);
3416 TearDownRetryVPCCheck( inMDNS
);
3418 inMDNS
->p
->initStatus
= err
;
3420 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
3421 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3425 //===========================================================================================================================
3426 // ProcessingThreadSetupWaitList
3427 //===========================================================================================================================
3429 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
3434 HANDLE
* waitItemPtr
;
3435 mDNSInterfaceData
* ifd
;
3438 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
3441 check( outWaitList
);
3442 check( outWaitListCount
);
3444 // Allocate an array to hold all the objects to wait on.
3446 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->timersCount
+ inMDNS
->p
->interfaceCount
+ gTCPConnections
;
3447 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
3448 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
3449 waitItemPtr
= waitList
;
3451 // Add the fixed wait items to the beginning of the list.
3453 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
3454 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
3455 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
3456 *waitItemPtr
++ = inMDNS
->p
->descChangedEvent
;
3457 *waitItemPtr
++ = inMDNS
->p
->tcpipChangedEvent
;
3458 *waitItemPtr
++ = inMDNS
->p
->ddnsChangedEvent
;
3462 if ( inMDNS
->p
->vpcCheckEvent
)
3464 *waitItemPtr
++ = inMDNS
->p
->vpcCheckEvent
;
3467 // Append all the dynamic wait items to the list.
3468 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3469 *waitItemPtr
++ = inMDNS
->p
->unicastSock4ReadEvent
;
3472 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3473 *waitItemPtr
++ = inMDNS
->p
->unicastSock6ReadEvent
;
3476 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3478 *waitItemPtr
++ = ifd
->readPendingEvent
;
3481 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3483 *waitItemPtr
++ = tcd
->pendingEvent
;
3486 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
3488 *outWaitList
= waitList
;
3489 *outWaitListCount
= waitListCount
;
3491 err
= mStatus_NoError
;
3498 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
3502 //===========================================================================================================================
3503 // ProcessingThreadProcessPacket
3504 //===========================================================================================================================
3506 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
)
3509 const mDNSInterfaceID iid
= inIFD
? inIFD
->interfaceInfo
.InterfaceID
: NULL
;
3510 LPFN_WSARECVMSG recvMsgPtr
;
3516 struct sockaddr_storage addr
;
3522 check( IsValidSocket( inSock
) );
3524 // Set up the default in case the packet info options are not supported or reported correctly.
3528 recvMsgPtr
= inIFD
->wsaRecvMsgFunctionPtr
;
3529 dstAddr
= inIFD
->defaultAddr
;
3530 dstPort
= MulticastDNSPort
;
3533 else if ( inSock
== inMDNS
->p
->unicastSock4
)
3535 recvMsgPtr
= inMDNS
->p
->unicastSock4RecvMsgPtr
;
3536 dstAddr
= inMDNS
->p
->unicastSock4DestAddr
;
3537 dstPort
= zeroIPPort
;
3540 else if ( inSock
== inMDNS
->p
->unicastSock6
)
3542 recvMsgPtr
= inMDNS
->p
->unicastSock6RecvMsgPtr
;
3543 dstAddr
= inMDNS
->p
->unicastSock6DestAddr
;
3544 dstPort
= zeroIPPort
;
3549 dlog( kDebugLevelError
, DEBUG_NAME
"packet received on unknown socket\n" );
3553 #if( !TARGET_OS_WINDOWS_CE )
3558 uint8_t controlBuffer
[ 128 ];
3560 LPWSACMSGHDR header
;
3562 // Set up the buffer and read the packet.
3564 msg
.name
= (LPSOCKADDR
) &addr
;
3565 msg
.namelen
= (INT
) sizeof( addr
);
3566 buf
.buf
= (char *) &packet
;
3567 buf
.len
= (u_long
) sizeof( packet
);
3568 msg
.lpBuffers
= &buf
;
3569 msg
.dwBufferCount
= 1;
3570 msg
.Control
.buf
= (char *) controlBuffer
;
3571 msg
.Control
.len
= (u_long
) sizeof( controlBuffer
);
3574 err
= recvMsgPtr( inSock
, &msg
, &size
, NULL
, NULL
);
3575 err
= translate_errno( err
== 0, (OSStatus
) GetLastError(), kUnknownErr
);
3576 require_noerr( err
, exit
);
3579 // Parse the control information. Reject packets received on the wrong interface.
3581 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
3583 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3585 IN_PKTINFO
* ipv4PacketInfo
;
3587 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3591 require_action( ipv4PacketInfo
->ipi_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
3594 dstAddr
.type
= mDNSAddrType_IPv4
;
3595 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3597 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3599 IN6_PKTINFO
* ipv6PacketInfo
;
3601 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3605 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( inIFD
->index
- kIPv6IfIndexBase
), exit
, err
= kMismatchErr
);
3608 dstAddr
.type
= mDNSAddrType_IPv6
;
3609 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3618 addrSize
= sizeof( addr
);
3619 n
= recvfrom( inSock
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
3620 err
= translate_errno( n
> 0, errno_compat(), kUnknownErr
);
3621 require_noerr( err
, exit
);
3623 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
3625 // Dispatch the packet to mDNS.
3627 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3628 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
3629 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3630 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3634 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &inIFD
->interfaceInfo
.ip
, (int) inIFD
->index
);
3637 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3639 end
= ( (mDNSu8
*) &packet
) + n
;
3640 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3646 //===========================================================================================================================
3647 // ProcessingThreadInterfaceListChanged
3648 //===========================================================================================================================
3650 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
3654 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3657 if (inMDNS
->p
->interfaceListChangedCallback
)
3659 inMDNS
->p
->interfaceListChangedCallback(inMDNS
);
3662 mDNSPlatformLock( inMDNS
);
3664 // Tear down the existing interfaces and set up new ones using the new IP info.
3666 err
= TearDownInterfaceList( inMDNS
);
3669 err
= SetupInterfaceList( inMDNS
);
3672 err
= uDNS_SetupDNSConfig( inMDNS
);
3675 // so that LLQs are restarted against the up to date name servers
3677 mDNS_UpdateLLQs( inMDNS
);
3679 mDNSPlatformUnlock( inMDNS
);
3681 // Inform clients of the change.
3683 if( inMDNS
->MainCallback
)
3685 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
3688 // Force mDNS to update.
3690 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
3694 //===========================================================================================================================
3695 // ProcessingThreadComputerDescriptionChanged
3696 //===========================================================================================================================
3697 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
*inMDNS
)
3701 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3704 mDNSPlatformLock( inMDNS
);
3707 SetupNiceName( inMDNS
);
3709 if (inMDNS
->p
->hostDescriptionChangedCallback
)
3711 inMDNS
->p
->hostDescriptionChangedCallback(inMDNS
);
3714 // and reset the event handler
3715 if ((inMDNS
->p
->descKey
!= NULL
) && (inMDNS
->p
->descChangedEvent
))
3717 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3721 mDNSPlatformUnlock( inMDNS
);
3725 //===========================================================================================================================
3726 // ProcessingThreadTCPIPConfigChanged
3727 //===========================================================================================================================
3728 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
)
3732 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3735 mDNSPlatformLock( inMDNS
);
3737 err
= uDNS_SetupDNSConfig( inMDNS
);
3740 // so that LLQs are restarted against the up to date name servers
3742 mDNS_UpdateLLQs( inMDNS
);
3744 // and reset the event handler
3746 if ( ( inMDNS
->p
->tcpipKey
!= NULL
) && ( inMDNS
->p
->tcpipChangedEvent
) )
3748 err
= RegNotifyChangeKeyValue( inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3752 mDNSPlatformUnlock( inMDNS
);
3756 //===========================================================================================================================
3757 // ProcessingThreadDynDNSConfigChanged
3758 //===========================================================================================================================
3759 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
*inMDNS
)
3763 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3766 SetDomainSecrets( inMDNS
);
3768 mDNSPlatformLock( inMDNS
);
3770 err
= uDNS_SetupDNSConfig( inMDNS
);
3773 // so that LLQs are restarted against the up to date name servers
3775 mDNS_UpdateLLQs( inMDNS
);
3777 // and reset the event handler
3779 if ((inMDNS
->p
->ddnsKey
!= NULL
) && (inMDNS
->p
->ddnsChangedEvent
))
3781 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3785 mDNSPlatformUnlock( inMDNS
);
3789 //===========================================================================================================================
3790 // ProcessingThreadRetryVPCCheck
3791 //===========================================================================================================================
3794 ProcessingThreadRetryVPCCheck( mDNS
* inMDNS
)
3796 mStatus err
= mStatus_NoError
;
3798 dlog( kDebugLevelTrace
, DEBUG_NAME
"in ProcessingThreadRetryVPCCheck\n" );
3800 TearDownRetryVPCCheck( inMDNS
);
3802 if ( inMDNS
->p
->vpcCheckCount
< kRetryVPCMax
)
3804 inMDNS
->p
->vpcCheckCount
++;
3806 err
= IsVPCRunning( &inMDNS
->p
->inVirtualPC
);
3807 require_noerr( err
, exit
);
3809 if ( inMDNS
->p
->inVirtualPC
)
3811 ProcessingThreadInterfaceListChanged( inMDNS
);
3819 SetupRetryVPCCheck( inMDNS
);
3829 #pragma mark == Utilities ==
3832 //===========================================================================================================================
3834 //===========================================================================================================================
3836 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
)
3840 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
3842 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3843 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3845 if( !gIPHelperLibraryInstance
)
3847 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
3848 if( gIPHelperLibraryInstance
)
3850 gGetAdaptersAddressesFunctionPtr
=
3851 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
3852 if( !gGetAdaptersAddressesFunctionPtr
)
3856 ok
= FreeLibrary( gIPHelperLibraryInstance
);
3857 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
3858 gIPHelperLibraryInstance
= NULL
;
3863 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3864 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
3866 if( !gGetAdaptersAddressesFunctionPtr
|| ( ( err
= getifaddrs_ipv6( outAddrs
) ) != mStatus_NoError
) )
3868 err
= getifaddrs_ipv4( outAddrs
);
3869 require_noerr( err
, exit
);
3872 #elif( !TARGET_OS_WINDOWS_CE )
3874 err
= getifaddrs_ipv4( outAddrs
);
3875 require_noerr( err
, exit
);
3879 err
= getifaddrs_ce( outAddrs
);
3880 require_noerr( err
, exit
);
3888 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3889 //===========================================================================================================================
3891 //===========================================================================================================================
3893 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
3898 struct ifaddrs
* head
;
3899 struct ifaddrs
** next
;
3900 IP_ADAPTER_ADDRESSES
* iaaList
;
3902 IP_ADAPTER_ADDRESSES
* iaa
;
3904 struct ifaddrs
* ifa
;
3906 check( gGetAdaptersAddressesFunctionPtr
);
3912 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3913 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3914 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3916 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
3921 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
3922 check( err
== ERROR_BUFFER_OVERFLOW
);
3923 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
3925 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
3926 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
3928 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
3929 if( err
== ERROR_SUCCESS
) break;
3934 require( i
< 100, exit
);
3935 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
3938 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
3941 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
3943 IP_ADAPTER_PREFIX
* firstPrefix
;
3945 if( iaa
->IfIndex
> 0xFFFFFF )
3947 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
3949 if( iaa
->Ipv6IfIndex
> 0xFF )
3951 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
3954 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3955 // following code to crash when iterating through the prefix list. This seems
3956 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3957 // This shouldn't happen according to Microsoft docs which states:
3959 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3961 // So the data structure seems to be corrupted when we return from
3962 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3963 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3964 // modify iaa to have the correct values.
3966 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
3968 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
3969 firstPrefix
= iaa
->FirstPrefix
;
3977 // Skip psuedo and tunnel interfaces.
3979 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
3984 // Add each address as a separate interface to emulate the way getifaddrs works.
3986 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
3990 IP_ADAPTER_PREFIX
* prefix
;
3993 family
= addr
->Address
.lpSockaddr
->sa_family
;
3994 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
3996 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3997 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4000 next
= &ifa
->ifa_next
;
4004 size
= strlen( iaa
->AdapterName
) + 1;
4005 ifa
->ifa_name
= (char *) malloc( size
);
4006 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4007 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
4009 // Get interface flags.
4012 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
4013 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
4014 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
4015 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
4018 // <rdar://problem/4045657> Interface index being returned is 512
4020 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
4021 // This code used to shift the IPv4 index up to ensure uniqueness between
4022 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
4023 // then see interface indexes passed back that don't correspond to anything
4024 // that is seen in Win32 APIs or command line tools like "route". As a relatively
4025 // small percentage of developers are actively using IPv6, it seems to
4026 // make sense to make our use of IPv4 as confusion free as possible.
4027 // So now, IPv6 interface indexes will be shifted up by a
4028 // constant value which will serve to uniquely identify them, and we will
4029 // leave IPv4 interface indexes unmodified.
4033 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
4034 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
4044 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
4045 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4046 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
4052 check( ifa
->ifa_addr
);
4054 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
4057 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
4059 if( prefixIndex
== addrIndex
)
4061 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
4062 prefixLength
= prefix
->PrefixLength
;
4070 struct sockaddr_in
* sa4
;
4072 require_action( prefixLength
<= 32, exit
, err
= ERROR_INVALID_DATA
);
4074 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
4075 require_action( sa4
, exit
, err
= WSAENOBUFS
);
4077 sa4
->sin_family
= AF_INET
;
4079 if ( prefixLength
!= 0 )
4081 sa4
->sin_addr
.s_addr
= htonl( 0xFFFFFFFFU
<< ( 32 - prefixLength
) );
4087 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv4 prefixLength is 0\n", __ROUTINE__
);
4088 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &index
, (struct sockaddr
*) sa4
);
4089 require_noerr( err
, exit
);
4092 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
4093 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
4099 struct sockaddr_in6
* sa6
;
4104 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
4106 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
4107 require_action( sa6
, exit
, err
= WSAENOBUFS
);
4108 sa6
->sin6_family
= AF_INET6
;
4110 if( prefixLength
== 0 )
4112 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
4116 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
4118 if( len
>= 8 ) maskByte
= 0xFF;
4119 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
4120 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
4122 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
4139 err
= ERROR_SUCCESS
;
4144 freeifaddrs( head
);
4150 return( (int) err
);
4153 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
4155 #if( !TARGET_OS_WINDOWS_CE )
4156 //===========================================================================================================================
4158 //===========================================================================================================================
4160 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
4166 INTERFACE_INFO
* buffer
;
4167 INTERFACE_INFO
* tempBuffer
;
4168 INTERFACE_INFO
* ifInfo
;
4171 struct ifaddrs
* head
;
4172 struct ifaddrs
** next
;
4173 struct ifaddrs
* ifa
;
4175 sock
= INVALID_SOCKET
;
4180 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4181 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4182 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4184 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4185 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4186 require_noerr( err
, exit
);
4189 size
= 16 * sizeof( INTERFACE_INFO
);
4192 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
4193 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
4194 buffer
= tempBuffer
;
4196 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
4203 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
4205 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
4207 check( actualSize
<= size
);
4208 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
4209 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
4211 // Process the raw interface list and build a linked list of IPv4 interfaces.
4213 for( i
= 0; i
< n
; ++i
)
4215 ifInfo
= &buffer
[ i
];
4216 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
4221 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4222 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4225 next
= &ifa
->ifa_next
;
4229 ifa
->ifa_name
= (char *) malloc( 16 );
4230 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4231 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4233 // Get interface flags.
4235 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4239 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
4241 struct sockaddr_in
* sa4
;
4243 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4244 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4245 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4246 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4248 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4250 // <rdar://problem/4076478> Service won't start on Win2K. The address
4251 // family field was not being initialized.
4253 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4254 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4255 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &ifa
->ifa_extra
.index
, ifa
->ifa_netmask
);
4256 require_noerr( err
, exit
);
4260 // Emulate an interface index.
4262 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4278 freeifaddrs( head
);
4284 if( sock
!= INVALID_SOCKET
)
4286 closesocket( sock
);
4290 #endif // !TARGET_OS_WINDOWS_CE )
4292 #if( TARGET_OS_WINDOWS_CE )
4293 //===========================================================================================================================
4295 //===========================================================================================================================
4297 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
4303 SOCKET_ADDRESS_LIST
* addressList
;
4304 struct ifaddrs
* head
;
4305 struct ifaddrs
** next
;
4306 struct ifaddrs
* ifa
;
4310 sock
= kInvalidSocketRef
;
4315 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4317 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4318 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4319 require_noerr( err
, exit
);
4321 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4322 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4324 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4327 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
4328 require_action( size
> 0, exit
, err
= -1 );
4331 buffer
= calloc( 1, size
);
4332 require_action( buffer
, exit
, err
= -1 );
4334 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4336 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
4337 require_noerr( err
, exit
);
4338 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
4340 // Process the raw interface list and build a linked list of interfaces.
4342 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4344 n
= addressList
->iAddressCount
;
4349 for( i
= 0; i
< n
; ++i
)
4351 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4352 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4355 next
= &ifa
->ifa_next
;
4359 ifa
->ifa_name
= (char *) malloc( 16 );
4360 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4361 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4363 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4365 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
4369 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
4373 struct sockaddr_in
* sa4
;
4375 sa4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
4376 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4377 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4378 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4399 freeifaddrs( head
);
4405 if( sock
!= INVALID_SOCKET
)
4407 closesocket( sock
);
4411 #endif // TARGET_OS_WINDOWS_CE )
4413 //===========================================================================================================================
4415 //===========================================================================================================================
4417 mDNSlocal
void freeifaddrs( struct ifaddrs
*inIFAs
)
4422 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4424 for( p
= inIFAs
; p
; p
= q
)
4430 free( p
->ifa_name
);
4435 free( p
->ifa_addr
);
4438 if( p
->ifa_netmask
)
4440 free( p
->ifa_netmask
);
4441 p
->ifa_netmask
= NULL
;
4443 if( p
->ifa_broadaddr
)
4445 free( p
->ifa_broadaddr
);
4446 p
->ifa_broadaddr
= NULL
;
4448 if( p
->ifa_dstaddr
)
4450 free( p
->ifa_dstaddr
);
4451 p
->ifa_dstaddr
= NULL
;
4455 free( p
->ifa_data
);
4463 //===========================================================================================================================
4464 // GetPrimaryInterface
4465 //===========================================================================================================================
4468 GetPrimaryInterface()
4470 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4472 BOOL bOrder
= FALSE
;
4476 unsigned long int i
;
4478 // Find out how big our buffer needs to be.
4480 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4481 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4483 // Allocate the memory for the table
4485 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4486 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4488 // Now get the table.
4490 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4491 require_noerr( err
, exit
);
4494 // Search for the row in the table we want.
4496 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4498 // Look for a default route
4500 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4502 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4507 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4508 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4514 if ( pIpForwardTable
!= NULL
)
4516 free( pIpForwardTable
);
4523 //===========================================================================================================================
4524 // AddressToIndexAndMask
4525 //===========================================================================================================================
4528 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4530 // Before calling AddIPAddress we use GetIpAddrTable to get
4531 // an adapter to which we can add the IP.
4533 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4535 mStatus err
= mStatus_UnknownErr
;
4538 // For now, this is only for IPv4 addresses. That is why we can safely cast
4539 // addr's to sockaddr_in.
4541 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4543 // Make an initial call to GetIpAddrTable to get the
4544 // necessary size into the dwSize variable
4546 for ( i
= 0; i
< 100; i
++ )
4548 err
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
4550 if ( err
!= ERROR_INSUFFICIENT_BUFFER
)
4555 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4556 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4559 require_noerr( err
, exit
);
4561 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4563 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4565 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4566 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4567 err
= mStatus_NoError
;
4576 free( pIPAddrTable
);
4583 //===========================================================================================================================
4584 // CanReceiveUnicast
4585 //===========================================================================================================================
4587 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4591 struct sockaddr_in addr
;
4593 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4595 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4596 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4597 ok
= IsValidSocket( sock
);
4600 memset( &addr
, 0, sizeof( addr
) );
4601 addr
.sin_family
= AF_INET
;
4602 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4603 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4605 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4606 close_compat( sock
);
4609 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4614 //===========================================================================================================================
4616 //===========================================================================================================================
4618 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4620 struct ifaddrs
* addrs
= NULL
;
4621 struct ifaddrs
* p
= NULL
;
4623 mDNSBool ret
= mDNSfalse
;
4625 // For now, only works for IPv4 interfaces
4627 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4629 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4631 err
= getifaddrs_ipv4( &addrs
);
4632 require_noerr( err
, exit
);
4634 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4636 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4637 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4639 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4649 freeifaddrs( addrs
);
4656 //===========================================================================================================================
4657 // GetWindowsVersionString
4658 //===========================================================================================================================
4660 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4662 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4663 #define VER_PLATFORM_WIN32_CE 3
4667 OSVERSIONINFO osInfo
;
4669 const char * versionString
;
4675 versionString
= "unknown Windows version";
4677 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4678 ok
= GetVersionEx( &osInfo
);
4679 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4680 require_noerr( err
, exit
);
4682 platformID
= osInfo
.dwPlatformId
;
4683 majorVersion
= osInfo
.dwMajorVersion
;
4684 minorVersion
= osInfo
.dwMinorVersion
;
4685 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4687 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4689 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4691 versionString
= "Windows 95";
4693 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4695 versionString
= "Windows 95 SP1";
4697 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4699 versionString
= "Windows 95 OSR2";
4701 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4703 versionString
= "Windows 98";
4705 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4707 versionString
= "Windows 98 SP1";
4709 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4711 versionString
= "Windows 98 SE";
4713 else if( minorVersion
== 90 )
4715 versionString
= "Windows ME";
4718 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4720 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4722 versionString
= "Windows NT 3.51";
4724 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4726 versionString
= "Windows NT 4";
4728 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4730 versionString
= "Windows 2000";
4732 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4734 versionString
= "Windows XP";
4736 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4738 versionString
= "Windows Server 2003";
4741 else if( platformID
== VER_PLATFORM_WIN32_CE
)
4743 versionString
= "Windows CE";
4747 if( inBuffer
&& ( inBufferSize
> 0 ) )
4750 strncpy( inBuffer
, versionString
, inBufferSize
);
4751 inBuffer
[ inBufferSize
] = '\0';
4757 //===========================================================================================================================
4759 //===========================================================================================================================
4762 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
4768 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
4779 *string
= (char*) malloc( *stringLen
);
4780 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
4782 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
4786 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
4788 require_noerr_quiet( err
, exit
);
4792 DWORD dwSize
= sizeof( DWORD
);
4794 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
4806 //===========================================================================================================================
4808 //===========================================================================================================================
4810 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
4812 struct sockaddr_in6 sa6
;
4813 struct sockaddr_in sa4
;
4817 sa6
.sin6_family
= AF_INET6
;
4818 dwSize
= sizeof( sa6
);
4820 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
4822 if ( err
== mStatus_NoError
)
4824 err
= SetupAddr( ip
, (struct sockaddr
*) &sa6
);
4825 require_noerr( err
, exit
);
4829 sa4
.sin_family
= AF_INET
;
4830 dwSize
= sizeof( sa4
);
4832 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
4833 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
4834 require_noerr( err
, exit
);
4836 err
= SetupAddr( ip
, (struct sockaddr
*) &sa4
);
4837 require_noerr( err
, exit
);
4846 //===========================================================================================================================
4848 //===========================================================================================================================
4850 mDNSlocal
struct ifaddrs
*
4851 myGetIfAddrs(int refresh
)
4853 static struct ifaddrs
*ifa
= NULL
;
4870 //===========================================================================================================================
4872 //===========================================================================================================================
4875 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
4877 #if( defined( UNICODE ) || defined( _UNICODE ) )
4881 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4882 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4883 require_noerr( err
, exit
);
4888 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
4893 //===========================================================================================================================
4894 // WindowsLatin1toUTF8
4895 //===========================================================================================================================
4898 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
4906 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4908 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
4909 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4910 require_noerr( err
, exit
);
4912 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
4913 require_action( utf16
, exit
, err
= kNoMemoryErr
);
4915 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
4916 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4917 require_noerr( err
, exit
);
4919 // Now convert the temporary UTF-16 to UTF-8.
4921 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4922 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4923 require_noerr( err
, exit
);
4926 if( utf16
) free( utf16
);
4931 //===========================================================================================================================
4932 // ConvertUTF8ToLsaString
4933 //===========================================================================================================================
4936 MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
)
4944 output
->Buffer
= NULL
;
4946 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, NULL
, 0 );
4947 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
4948 require_noerr( err
, exit
);
4950 output
->Length
= (USHORT
)( size
* sizeof( wchar_t ) );
4951 output
->Buffer
= (PWCHAR
) malloc( output
->Length
);
4952 require_action( output
->Buffer
, exit
, err
= mStatus_NoMemoryErr
);
4953 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, output
->Buffer
, size
);
4954 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
4955 require_noerr( err
, exit
);
4957 // We're going to subtrace one wchar_t from the size, because we didn't
4958 // include it when we encoded the string
4960 output
->MaximumLength
= output
->Length
;
4961 output
->Length
-= sizeof( wchar_t );
4965 if ( err
&& output
->Buffer
)
4967 free( output
->Buffer
);
4968 output
->Buffer
= NULL
;
4975 //===========================================================================================================================
4976 // ConvertLsaStringToUTF8
4977 //===========================================================================================================================
4980 MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
)
4983 OSStatus err
= kNoErr
;
4985 // The Length field of this structure holds the number of bytes,
4986 // but WideCharToMultiByte expects the number of wchar_t's. So
4987 // we divide by sizeof(wchar_t) to get the correct number.
4989 size
= (size_t) WideCharToMultiByte(CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), NULL
, 0, NULL
, NULL
);
4990 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
4991 require_noerr( err
, exit
);
4993 // Ensure that we have enough space (Add one for trailing '\0')
4995 require_action( ( size
+ 1 ) <= len
, exit
, err
= mStatus_NoMemoryErr
);
4997 // Convert the string
4999 size
= (size_t) WideCharToMultiByte( CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), output
, (int) size
, NULL
, NULL
);
5000 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
5001 require_noerr( err
, exit
);
5003 // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
5004 // although it does return the correct size
5006 output
[size
] = '\0';
5014 //===========================================================================================================================
5015 // FreeTCPConnectionData
5016 //===========================================================================================================================
5019 FreeTCPSocket( TCPSocket
*sock
)
5023 if ( sock
->pendingEvent
)
5025 CloseHandle( sock
->pendingEvent
);
5028 if ( sock
->fd
!= INVALID_SOCKET
)
5030 closesocket( sock
->fd
);
5036 //===========================================================================================================================
5038 //===========================================================================================================================
5040 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
5042 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
5044 if (sa
->sa_family
== AF_INET
)
5046 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
5047 ip
->type
= mDNSAddrType_IPv4
;
5048 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
5049 return(mStatus_NoError
);
5052 if (sa
->sa_family
== AF_INET6
)
5054 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
5055 ip
->type
= mDNSAddrType_IPv6
;
5056 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.u
.Word
[1] = 0;
5057 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
5058 return(mStatus_NoError
);
5061 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
5062 return(mStatus_Invalid
);