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.145 2009/07/20 04:07:41 herscher
21 <rdar://problem/6145339> Bonjour does not list IPv6 loopback address when all network adapters are disabled
23 Revision 1.144 2009/07/17 19:59:46 herscher
24 <rdar://problem/7062660> Update the womp settings for each network adapter immediately preceding the call to mDNSCoreMachineSleep().
26 Revision 1.143 2009/07/07 21:34:58 herscher
27 <rdar://problem/6713286> windows platform changes to support use as sleep proxy client
29 Revision 1.142 2009/06/25 21:11:02 herscher
30 <rdar://problem/7003607> Platform layer doesn't correctly initialize the port field of TCP and UDP socket structures.
32 Revision 1.141 2009/06/22 23:25:05 herscher
33 <rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
35 Revision 1.140 2009/04/24 04:55:26 herscher
36 <rdar://problem/3496833> Advertise SMB file sharing via Bonjour
38 Revision 1.139 2009/04/01 20:06:31 herscher
39 <rdar://problem/5629676> Corrupt computer name string used
41 Revision 1.138 2009/04/01 19:31:54 herscher
42 Remove extraneous printf
44 Revision 1.137 2009/04/01 17:50:15 mcguire
47 Revision 1.136 2009/03/30 20:53:10 herscher
48 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
49 <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8.
50 <rdar://problem/6145992> Reduce sleep from 3 seconds to 2 seconds
51 <rdar://problem/6145992> Bonjour Service sometimes only gets a IPv6 link-local address after a network changed event
52 <rdar://problem/6145913> Bonjour For Windows doesn't show IPv4 loopback intermittently when no network interfaces are active
53 <rdar://problem/6143633> Bonjour service does not publish ANY IPv6 address on Windows Vista
54 <rdar://problem/6136296> Bonjour 105A6: mDNSResponder is crashing on startup
55 <rdar://problem/6127927> B4Windows: uDNS: Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
56 <rdar://problem/5270738> Remove Virtual PC check from mDNSResponder code
58 Revision 1.135 2009/01/13 05:31:35 mkrochma
59 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
61 Revision 1.134 2008/10/23 22:33:25 cheshire
62 Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
64 Revision 1.133 2008/10/22 17:19:57 cheshire
65 Don't need to define BPF_fd any more (it's now per-interface, not global)
67 Revision 1.132 2008/10/03 23:34:08 cheshire
68 Added skeleton definition of mDNSPlatformSendRawPacket
70 Revision 1.131 2008/10/03 18:25:18 cheshire
71 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
73 Revision 1.130 2007/11/16 18:53:56 cheshire
74 TCPSocketFlags needs to be first field of TCPSocket_struct
76 Revision 1.129 2007/10/17 22:52:26 cheshire
77 Get rid of unused mDNS_UpdateLLQs()
79 Revision 1.128 2007/09/12 19:23:17 cheshire
80 Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
82 Revision 1.127 2007/07/20 00:54:22 cheshire
83 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
85 Revision 1.126 2007/07/11 02:56:20 cheshire
86 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
87 Remove unused mDNSPlatformDefaultRegDomainChanged
89 Revision 1.125 2007/06/20 01:10:13 cheshire
90 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
92 Revision 1.124 2007/04/26 00:35:16 cheshire
93 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
94 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
95 inside the firewall may give answers where a public one gives none, and vice versa.)
97 Revision 1.123 2007/04/18 21:00:40 cheshire
98 Use mDNS_AddSearchDomain_CString() instead of MakeDomainNameFromDNSNameString ... mDNS_AddSearchDomain
100 Revision 1.122 2007/04/17 19:21:29 cheshire
101 <rdar://problem/5140339> Domain discovery not working over VPN
103 Revision 1.121 2007/04/05 20:40:37 cheshire
104 Remove unused mDNSPlatformTCPGetFlags()
106 Revision 1.120 2007/03/28 20:59:27 cheshire
107 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
109 Revision 1.119 2007/03/28 15:56:38 cheshire
110 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
112 Revision 1.118 2007/03/22 18:31:49 cheshire
113 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
115 Revision 1.117 2007/03/21 00:30:07 cheshire
116 <rdar://problem/4789455> Multiple errors in DNameList-related code
118 Revision 1.116 2007/03/20 17:07:16 cheshire
119 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
121 Revision 1.115 2007/02/08 21:12:28 cheshire
122 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
124 Revision 1.114 2007/01/05 08:31:01 cheshire
125 Trim excessive "$Log" checkin history from before 2006
126 (checkin history still available via "cvs log ..." of course)
128 Revision 1.113 2007/01/04 23:12:20 cheshire
129 Remove unused mDNSPlatformDefaultBrowseDomainChanged
131 Revision 1.112 2006/12/22 20:59:51 cheshire
132 <rdar://problem/4742742> Read *all* DNS keys from keychain,
133 not just key for the system-wide default registration domain
135 Revision 1.111 2006/12/19 22:43:56 cheshire
136 Fix compiler warnings
138 Revision 1.110 2006/09/27 00:47:40 herscher
139 Fix compile error caused by changes to the tcp callback api.
141 Revision 1.109 2006/08/14 23:25:21 cheshire
142 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
144 Revision 1.108 2006/07/06 00:06:21 cheshire
145 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
147 Revision 1.107 2006/03/19 02:00:13 cheshire
148 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
150 Revision 1.106 2006/02/26 19:31:05 herscher
151 <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.
155 - Get unicode name of machine for nice name instead of just the host name.
156 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
157 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
158 - Implement TCP support for truncated packets (only stubs now).
168 #include "CommonServices.h"
169 #include "DebugServices.h"
170 #include "Firewall.h"
171 #include "RegNames.h"
175 #include <Iphlpapi.h>
176 #if( !TARGET_OS_WINDOWS_CE )
179 #include <ntsecapi.h>
181 #include <winioctl.h>
182 #include <ntddndis.h> // This defines the IOCTL constants.
185 #include "mDNSEmbeddedAPI.h"
186 #include "DNSCommon.h"
187 #include "mDNSWin32.h"
190 #pragma mark == Constants ==
193 //===========================================================================================================================
195 //===========================================================================================================================
197 #define DEBUG_NAME "[mDNSWin32] "
199 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
200 #define MDNS_WINDOWS_ENABLE_IPV4 1
201 #define MDNS_WINDOWS_ENABLE_IPV6 1
202 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
203 #define MDNS_SET_HINFO_STRINGS 0
205 #define kMDNSDefaultName "My Computer"
207 #define kWinSockMajorMin 2
208 #define kWinSockMinorMin 2
210 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
211 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
212 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
213 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
214 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
215 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
216 #define kWaitListFileShareEvent ( WAIT_OBJECT_0 + 6 )
217 #define kWaitListFirewallEvent ( WAIT_OBJECT_0 + 7 )
218 #define kWaitListFixedItemCount 8 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
220 #define kRegistryMaxKeyLength 255
221 #define kRegistryMaxValueName 16383
223 #if( !TARGET_OS_WINDOWS_CE )
224 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
227 #define kIPv6IfIndexBase (10000000L)
228 #define SMBPortAsNumber 445
229 #define DEVICE_PREFIX "\\\\.\\"
233 #pragma mark == Prototypes ==
236 //===========================================================================================================================
238 //===========================================================================================================================
240 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
241 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
242 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
243 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
244 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
245 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
246 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
247 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
248 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
249 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
250 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
251 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
252 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
254 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
255 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
256 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
257 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
258 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
259 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, UDPSocket
* inUDPSocket
, SocketRef inSock
);
260 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
261 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
* inMDNS
);
262 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
);
263 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
* inMDNS
);
264 mDNSlocal
void ProcessingThreadFileShareChanged( mDNS
* inMDNS
);
265 mDNSlocal
void ProcessingThreadFirewallChanged( mDNS
* inMDNS
);
266 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
);
268 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
);
269 mDNSlocal
void freeifaddrs( struct ifaddrs
*inAddrs
);
273 // Platform Accessors
279 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
280 struct mDNSPlatformInterfaceInfo
286 struct TCPSocket_struct
288 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
291 TCPConnectionCallback callback
;
297 struct UDPSocket_struct
299 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
303 LPFN_WSARECVMSG recvMsgPtr
;
304 struct UDPSocket_struct
* next
;
311 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
312 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
316 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
317 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
320 #if( !TARGET_OS_WINDOWS_CE )
321 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
324 #if( TARGET_OS_WINDOWS_CE )
325 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
328 mDNSlocal DWORD
GetPrimaryInterface();
329 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
330 mDNSlocal mDNSBool
CanReceiveUnicast( void );
331 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
333 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
334 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
335 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
336 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
337 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
338 mDNSlocal
void FreeTCPSocket( TCPSocket
*sock
);
339 mDNSlocal
void FreeUDPSocket( UDPSocket
* sock
);
340 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
);
341 mDNSlocal
void GetDDNSFQDN( domainname
*const fqdn
);
343 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCWSTR lpSubKey
);
345 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCSTR lpSubKey
);
347 mDNSlocal
void SetDomainSecrets( mDNS
* const m
);
348 mDNSlocal
void SetDomainSecret( mDNS
* const m
, const domainname
* inDomain
);
349 mDNSlocal
void CheckFileShares( mDNS
* const m
);
350 mDNSlocal mDNSu8
IsWOMPEnabled( const char * adapterName
);
357 #pragma mark == Globals ==
360 //===========================================================================================================================
362 //===========================================================================================================================
364 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
365 mDNSs32 mDNSPlatformOneSecond
= 0;
366 mDNSlocal TCPSocket
* gTCPConnectionList
= NULL
;
367 mDNSlocal
int gTCPConnections
= 0;
368 mDNSlocal UDPSocket
* gUDPSocketList
= NULL
;
369 mDNSlocal
int gUDPSockets
= 0;
370 mDNSlocal BOOL gWaitListChanged
= FALSE
;
372 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
375 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
379 PIP_ADAPTER_ADDRESSES inAdapter
,
380 PULONG outBufferSize
);
382 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
383 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
389 typedef ULONG_PTR HCRYPTPROV
; // WinCrypt.h, line 249
393 #ifndef CRYPT_MACHINE_KEYSET
394 # define CRYPT_MACHINE_KEYSET 0x00000020
397 #ifndef CRYPT_NEWKEYSET
398 # define CRYPT_NEWKEYSET 0x00000008
401 #ifndef PROV_RSA_FULL
402 # define PROV_RSA_FULL 1
405 typedef BOOL (__stdcall
*fnCryptGenRandom
)( HCRYPTPROV
, DWORD
, BYTE
* );
406 typedef BOOL (__stdcall
*fnCryptAcquireContext
)( HCRYPTPROV
*, LPCTSTR
, LPCTSTR
, DWORD
, DWORD
);
407 typedef BOOL (__stdcall
*fnCryptReleaseContext
)(HCRYPTPROV
, DWORD
);
409 static fnCryptAcquireContext g_lpCryptAcquireContext
= NULL
;
410 static fnCryptReleaseContext g_lpCryptReleaseContext
= NULL
;
411 static fnCryptGenRandom g_lpCryptGenRandom
= NULL
;
412 static HINSTANCE g_hAAPI32
= NULL
;
413 static HCRYPTPROV g_hProvider
= ( ULONG_PTR
) NULL
;
418 #pragma mark == Platform Support ==
421 //===========================================================================================================================
423 //===========================================================================================================================
425 mDNSexport mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
430 struct sockaddr_in sa4
;
431 struct sockaddr_in6 sa6
;
435 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
437 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
438 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
440 mDNSPlatformMemZero( &gMDNSPlatformSupport
, sizeof( gMDNSPlatformSupport
) );
441 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
442 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
443 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
445 // Startup WinSock 2.2 or later.
447 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
448 require_noerr( err
, exit
);
450 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
451 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
453 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
455 // Setup the HINFO HW/SW strings.
457 #if ( MDNS_SET_HINFO_STRINGS )
458 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
460 // Note that GetWindowsVersionString guarantees that the resulting string is always null-terminated,
461 // so the following strlen call is safe
462 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
463 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
465 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
466 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
467 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
468 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
471 // Set up the IPv4 unicast socket
473 inMDNS
->p
->unicastSock4
= INVALID_SOCKET
;
474 inMDNS
->p
->unicastSock4ReadEvent
= NULL
;
475 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
477 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
479 sa4
.sin_family
= AF_INET
;
480 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
481 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
);
483 sa4len
= sizeof( sa4
);
484 err
= getsockname( inMDNS
->p
->unicastSock4
, (struct sockaddr
*) &sa4
, &sa4len
);
485 require_noerr( err
, exit
);
486 inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
487 inMDNS
->p
->unicastSock4ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
488 err
= translate_errno( inMDNS
->p
->unicastSock4ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
489 require_noerr( err
, exit
);
490 err
= WSAEventSelect( inMDNS
->p
->unicastSock4
, inMDNS
->p
->unicastSock4ReadEvent
, FD_READ
);
491 require_noerr( err
, exit
);
492 #if( !TARGET_OS_WINDOWS_CE )
496 err
= WSAIoctl( inMDNS
->p
->unicastSock4
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
497 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock4RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock4RecvMsgPtr
), &size
, NULL
, NULL
);
501 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
508 // Set up the IPv6 unicast socket
510 inMDNS
->p
->unicastSock6
= INVALID_SOCKET
;
511 inMDNS
->p
->unicastSock6ReadEvent
= NULL
;
512 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
514 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
516 sa6
.sin6_family
= AF_INET6
;
517 sa6
.sin6_addr
= in6addr_any
;
518 sa6
.sin6_scope_id
= 0;
520 // This call will fail if the machine hasn't installed IPv6. In that case,
521 // the error will be WSAEAFNOSUPPORT.
523 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
);
524 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
525 inMDNS
->p
->unicastSock6ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
526 err
= translate_errno( inMDNS
->p
->unicastSock6ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
527 require_noerr( err
, exit
);
529 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
531 if ( inMDNS
->p
->unicastSock6
!= INVALID_SOCKET
)
533 sa6len
= sizeof( sa6
);
534 err
= getsockname( inMDNS
->p
->unicastSock6
, (struct sockaddr
*) &sa6
, &sa6len
);
535 require_noerr( err
, exit
);
536 inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
538 err
= WSAEventSelect( inMDNS
->p
->unicastSock6
, inMDNS
->p
->unicastSock6ReadEvent
, FD_READ
);
539 require_noerr( err
, exit
);
541 #if( !TARGET_OS_WINDOWS_CE )
545 err
= WSAIoctl( inMDNS
->p
->unicastSock6
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
546 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock6RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock6RecvMsgPtr
), &size
, NULL
, NULL
);
550 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
558 // Set up the mDNS thread.
560 err
= SetupSynchronizationObjects( inMDNS
);
561 require_noerr( err
, exit
);
563 err
= SetupThread( inMDNS
);
564 require_noerr( err
, exit
);
566 // Notify core of domain secret keys
568 SetDomainSecrets( inMDNS
);
572 mDNSCoreInitComplete( inMDNS
, err
);
574 // See if we need to advertise file sharing
576 inMDNS
->p
->smbRegistered
= mDNSfalse
;
577 CheckFileShares( inMDNS
);
582 mDNSPlatformClose( inMDNS
);
584 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
588 //===========================================================================================================================
590 //===========================================================================================================================
592 mDNSexport
void mDNSPlatformClose( mDNS
* const inMDNS
)
596 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
599 // Tear everything down in reverse order to how it was set up.
601 err
= TearDownThread( inMDNS
);
604 err
= TearDownInterfaceList( inMDNS
);
606 check( !inMDNS
->p
->inactiveInterfaceList
);
608 err
= TearDownSynchronizationObjects( inMDNS
);
611 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
613 if ( inMDNS
->p
->unicastSock4ReadEvent
)
615 CloseHandle( inMDNS
->p
->unicastSock4ReadEvent
);
616 inMDNS
->p
->unicastSock4ReadEvent
= 0;
619 if ( IsValidSocket( inMDNS
->p
->unicastSock4
) )
621 close_compat( inMDNS
->p
->unicastSock4
);
626 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
628 if ( inMDNS
->p
->unicastSock6ReadEvent
)
630 CloseHandle( inMDNS
->p
->unicastSock6ReadEvent
);
631 inMDNS
->p
->unicastSock6ReadEvent
= 0;
634 if ( IsValidSocket( inMDNS
->p
->unicastSock6
) )
636 close_compat( inMDNS
->p
->unicastSock6
);
641 // Free the DLL needed for IPv6 support.
643 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
644 if( gIPHelperLibraryInstance
)
646 gGetAdaptersAddressesFunctionPtr
= NULL
;
648 FreeLibrary( gIPHelperLibraryInstance
);
649 gIPHelperLibraryInstance
= NULL
;
655 // Release any resources
657 if ( g_hProvider
&& g_lpCryptReleaseContext
)
659 ( g_lpCryptReleaseContext
)( g_hProvider
, 0 );
662 // Free the AdvApi32.dll
664 FreeLibrary( g_hAAPI32
);
666 // And reset all the data
668 g_lpCryptAcquireContext
= NULL
;
669 g_lpCryptReleaseContext
= NULL
;
670 g_lpCryptGenRandom
= NULL
;
671 g_hProvider
= ( ULONG_PTR
) NULL
;
677 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
681 //===========================================================================================================================
683 //===========================================================================================================================
685 mDNSexport
void mDNSPlatformLock( const mDNS
* const inMDNS
)
689 if ( inMDNS
->p
->lockInitialized
)
691 EnterCriticalSection( &inMDNS
->p
->lock
);
695 //===========================================================================================================================
696 // mDNSPlatformUnlock
697 //===========================================================================================================================
699 mDNSexport
void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
704 if ( inMDNS
->p
->lockInitialized
)
706 check( inMDNS
->p
->threadID
);
708 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
709 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
711 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
715 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
716 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
718 LeaveCriticalSection( &inMDNS
->p
->lock
);
722 //===========================================================================================================================
723 // mDNSPlatformStrCopy
724 //===========================================================================================================================
726 mDNSexport
void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
731 strcpy( (char *) inDst
, (const char*) inSrc
);
734 //===========================================================================================================================
735 // mDNSPlatformStrLen
736 //===========================================================================================================================
738 mDNSexport mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
742 return( (mDNSu32
) strlen( (const char *) inSrc
) );
745 //===========================================================================================================================
746 // mDNSPlatformMemCopy
747 //===========================================================================================================================
749 mDNSexport
void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
754 memcpy( inDst
, inSrc
, inSize
);
757 //===========================================================================================================================
758 // mDNSPlatformMemSame
759 //===========================================================================================================================
761 mDNSexport mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
766 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
769 //===========================================================================================================================
770 // mDNSPlatformMemZero
771 //===========================================================================================================================
773 mDNSexport
void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
777 memset( inDst
, 0, inSize
);
780 //===========================================================================================================================
781 // mDNSPlatformMemAllocate
782 //===========================================================================================================================
784 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
790 mem
= malloc( inSize
);
796 //===========================================================================================================================
797 // mDNSPlatformMemFree
798 //===========================================================================================================================
800 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
807 //===========================================================================================================================
808 // mDNSPlatformRandomNumber
809 //===========================================================================================================================
811 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
813 mDNSu32 randomNumber
= 0;
819 g_hAAPI32
= LoadLibrary( TEXT("AdvAPI32.dll") );
820 err
= translate_errno( g_hAAPI32
!= NULL
, GetLastError(), mStatus_UnknownErr
);
821 require_noerr( err
, exit
);
824 // Function Pointer: CryptAcquireContext
826 if ( !g_lpCryptAcquireContext
)
828 g_lpCryptAcquireContext
= ( fnCryptAcquireContext
)
830 ( GetProcAddress( g_hAAPI32
, "CryptAcquireContextW" ) );
832 ( GetProcAddress( g_hAAPI32
, "CryptAcquireContextA" ) );
834 err
= translate_errno( g_lpCryptAcquireContext
!= NULL
, GetLastError(), mStatus_UnknownErr
);
835 require_noerr( err
, exit
);
838 // Function Pointer: CryptReleaseContext
840 if ( !g_lpCryptReleaseContext
)
842 g_lpCryptReleaseContext
= ( fnCryptReleaseContext
)
843 ( GetProcAddress( g_hAAPI32
, "CryptReleaseContext" ) );
844 err
= translate_errno( g_lpCryptReleaseContext
!= NULL
, GetLastError(), mStatus_UnknownErr
);
845 require_noerr( err
, exit
);
848 // Function Pointer: CryptGenRandom
850 if ( !g_lpCryptGenRandom
)
852 g_lpCryptGenRandom
= ( fnCryptGenRandom
)
853 ( GetProcAddress( g_hAAPI32
, "CryptGenRandom" ) );
854 err
= translate_errno( g_lpCryptGenRandom
!= NULL
, GetLastError(), mStatus_UnknownErr
);
855 require_noerr( err
, exit
);
862 bResult
= (*g_lpCryptAcquireContext
)( &g_hProvider
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
);
866 bResult
= ( *g_lpCryptAcquireContext
)( &g_hProvider
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_MACHINE_KEYSET
| CRYPT_NEWKEYSET
);
867 err
= translate_errno( bResult
, GetLastError(), mStatus_UnknownErr
);
868 require_noerr( err
, exit
);
872 bResult
= (*g_lpCryptGenRandom
)( g_hProvider
, sizeof( randomNumber
), ( BYTE
* ) &randomNumber
);
873 err
= translate_errno( bResult
, GetLastError(), mStatus_UnknownErr
);
874 require_noerr( err
, exit
);
880 randomNumber
= rand();
886 //===========================================================================================================================
887 // mDNSPlatformTimeInit
888 //===========================================================================================================================
890 mDNSexport mStatus
mDNSPlatformTimeInit( void )
892 // No special setup is required on Windows -- we just use GetTickCount().
893 return( mStatus_NoError
);
896 //===========================================================================================================================
897 // mDNSPlatformRawTime
898 //===========================================================================================================================
900 mDNSexport mDNSs32
mDNSPlatformRawTime( void )
902 return( (mDNSs32
) GetTickCount() );
905 //===========================================================================================================================
907 //===========================================================================================================================
909 mDNSexport mDNSs32
mDNSPlatformUTC( void )
911 return ( mDNSs32
) time( NULL
);
914 //===========================================================================================================================
915 // mDNSPlatformInterfaceNameToID
916 //===========================================================================================================================
918 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
921 mDNSInterfaceData
* ifd
;
927 // Search for an interface with the specified name,
929 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
931 if( strcmp( ifd
->name
, inName
) == 0 )
936 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
942 *outID
= (mDNSInterfaceID
) ifd
;
944 err
= mStatus_NoError
;
950 //===========================================================================================================================
951 // mDNSPlatformInterfaceIDToInfo
952 //===========================================================================================================================
954 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
957 mDNSInterfaceData
* ifd
;
963 // Search for an interface with the specified ID,
965 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
967 if( ifd
== (mDNSInterfaceData
*) inID
)
972 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
976 outInfo
->name
= ifd
->name
;
977 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
978 err
= mStatus_NoError
;
984 //===========================================================================================================================
985 // mDNSPlatformInterfaceIDfromInterfaceIndex
986 //===========================================================================================================================
988 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
* const inMDNS
, mDNSu32 inIndex
)
993 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
995 id
= mDNSInterface_LocalOnly
;
997 else if( inIndex
!= 0 )
999 mDNSInterfaceData
* ifd
;
1001 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1003 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
1005 id
= ifd
->interfaceInfo
.InterfaceID
;
1014 //===========================================================================================================================
1015 // mDNSPlatformInterfaceIndexfromInterfaceID
1016 //===========================================================================================================================
1018 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
* const inMDNS
, mDNSInterfaceID inID
)
1023 if( inID
== mDNSInterface_LocalOnly
)
1025 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
1029 mDNSInterfaceData
* ifd
;
1031 // Search active interfaces.
1032 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1034 if( (mDNSInterfaceID
) ifd
== inID
)
1036 index
= ifd
->scopeID
;
1041 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
1045 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
1047 if( (mDNSInterfaceID
) ifd
== inID
)
1049 index
= ifd
->scopeID
;
1059 //===========================================================================================================================
1060 // mDNSPlatformTCPSocket
1061 //===========================================================================================================================
1064 mDNSPlatformTCPSocket
1067 TCPSocketFlags flags
,
1071 TCPSocket
* sock
= NULL
;
1072 u_long on
= 1; // "on" for setsockopt
1073 struct sockaddr_in saddr
;
1075 mStatus err
= mStatus_NoError
;
1079 require_action( flags
== 0, exit
, err
= mStatus_UnsupportedErr
);
1081 // Setup connection data object
1083 sock
= (TCPSocket
*) malloc( sizeof( TCPSocket
) );
1084 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1085 mDNSPlatformMemZero( sock
, sizeof( TCPSocket
) );
1087 sock
->fd
= INVALID_SOCKET
;
1088 sock
->flags
= flags
;
1090 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1091 saddr
.sin_family
= AF_INET
;
1092 saddr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
1093 saddr
.sin_port
= port
->NotAnInteger
;
1095 // Create the socket
1097 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
1098 err
= translate_errno( sock
->fd
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
1099 require_noerr( err
, exit
);
1103 err
= bind( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1104 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1105 require_noerr( err
, exit
);
1107 // Set it to be non-blocking
1109 err
= ioctlsocket( sock
->fd
, FIONBIO
, &on
);
1110 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1111 require_noerr( err
, exit
);
1115 mDNSPlatformMemZero( &saddr
, sizeof( saddr
) );
1116 len
= sizeof( saddr
);
1118 err
= getsockname( sock
->fd
, ( struct sockaddr
* ) &saddr
, &len
);
1119 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1120 require_noerr( err
, exit
);
1122 port
->NotAnInteger
= saddr
.sin_port
;
1128 FreeTCPSocket( sock
);
1135 //===========================================================================================================================
1136 // mDNSPlatformTCPConnect
1137 //===========================================================================================================================
1140 mDNSPlatformTCPConnect
1143 const mDNSAddr
* inDstIP
,
1144 mDNSOpaque16 inDstPort
,
1145 mDNSInterfaceID inInterfaceID
,
1146 TCPConnectionCallback inCallback
,
1150 struct sockaddr_in saddr
;
1151 mStatus err
= mStatus_NoError
;
1153 DEBUG_UNUSED( inInterfaceID
);
1155 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1157 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1158 return mStatus_UnknownErr
;
1161 // Setup connection data object
1163 sock
->callback
= inCallback
;
1164 sock
->context
= inContext
;
1166 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1167 saddr
.sin_family
= AF_INET
;
1168 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1169 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1171 // Try and do connect
1173 err
= connect( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1174 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1175 sock
->connected
= !err
? TRUE
: FALSE
;
1176 sock
->pendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1177 err
= translate_errno( sock
->pendingEvent
, GetLastError(), mStatus_UnknownErr
);
1178 require_noerr( err
, exit
);
1179 err
= WSAEventSelect( sock
->fd
, sock
->pendingEvent
, FD_CONNECT
|FD_READ
|FD_CLOSE
);
1180 require_noerr( err
, exit
);
1184 sock
->next
= gTCPConnectionList
;
1185 gTCPConnectionList
= sock
;
1187 gWaitListChanged
= TRUE
;
1193 err
= sock
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1199 //===========================================================================================================================
1200 // mDNSPlatformTCPAccept
1201 //===========================================================================================================================
1204 mDNSexport TCPSocket
*mDNSPlatformTCPAccept( TCPSocketFlags flags
, int fd
)
1206 TCPSocket
* sock
= NULL
;
1207 mStatus err
= mStatus_NoError
;
1209 require_action( !flags
, exit
, err
= mStatus_UnsupportedErr
);
1211 sock
= malloc( sizeof( TCPSocket
) );
1212 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1214 mDNSPlatformMemZero( sock
, sizeof( *sock
) );
1217 sock
->flags
= flags
;
1231 //===========================================================================================================================
1232 // mDNSPlatformTCPCloseConnection
1233 //===========================================================================================================================
1235 mDNSexport
void mDNSPlatformTCPCloseConnection( TCPSocket
*sock
)
1237 TCPSocket
* inserted
= gTCPConnectionList
;
1238 TCPSocket
* last
= NULL
;
1242 if ( inserted
== sock
)
1246 gTCPConnectionList
= inserted
->next
;
1250 last
->next
= inserted
->next
;
1254 gWaitListChanged
= TRUE
;
1260 inserted
= inserted
->next
;
1263 FreeTCPSocket( sock
);
1266 //===========================================================================================================================
1267 // mDNSPlatformReadTCP
1268 //===========================================================================================================================
1270 mDNSexport
long mDNSPlatformReadTCP( TCPSocket
*sock
, void *inBuffer
, unsigned long inBufferSize
, mDNSBool
* closed
)
1274 nread
= recv( sock
->fd
, inBuffer
, inBufferSize
, 0);
1278 if ( WSAGetLastError() == WSAEWOULDBLOCK
)
1295 //===========================================================================================================================
1296 // mDNSPlatformWriteTCP
1297 //===========================================================================================================================
1299 mDNSexport
long mDNSPlatformWriteTCP( TCPSocket
*sock
, const char *inMsg
, unsigned long inMsgSize
)
1304 nsent
= send( sock
->fd
, inMsg
, inMsgSize
, 0 );
1306 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1307 require_noerr( err
, exit
);
1319 //===========================================================================================================================
1320 // mDNSPlatformTCPGetFD
1321 //===========================================================================================================================
1323 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1325 return ( int ) sock
->fd
;
1329 //===========================================================================================================================
1330 // mDNSPlatformUDPSocket
1331 //===========================================================================================================================
1333 mDNSexport UDPSocket
* mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
1335 UDPSocket
* sock
= NULL
;
1336 mDNSIPPort port
= requestedport
;
1337 mStatus err
= mStatus_NoError
;
1340 // Setup connection data object
1342 sock
= (struct UDPSocket_struct
*) malloc( sizeof( struct UDPSocket_struct
) );
1343 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1344 memset( sock
, 0, sizeof( struct UDPSocket_struct
) );
1346 // Create the socket
1348 sock
->recvMsgPtr
= m
->p
->unicastSock4RecvMsgPtr
;
1349 sock
->dstAddr
= m
->p
->unicastSock4DestAddr
;
1350 sock
->sock
= INVALID_SOCKET
;
1352 // Try at most 10000 times to get a unique random port
1354 for (i
=0; i
<10000; i
++)
1356 struct sockaddr_in saddr
;
1358 saddr
.sin_family
= AF_INET
;
1359 saddr
.sin_addr
.s_addr
= 0;
1361 // The kernel doesn't do cryptographically strong random port
1362 // allocation, so we do it ourselves here
1364 if (mDNSIPPortIsZero(requestedport
))
1366 port
= mDNSOpaque16fromIntVal( ( mDNSu16
) ( 0xC000 + mDNSRandom(0x3FFF) ) );
1369 saddr
.sin_port
= port
.NotAnInteger
;
1371 err
= SetupSocket(m
, ( struct sockaddr
* ) &saddr
, port
, &sock
->sock
);
1375 require_noerr( err
, exit
);
1381 // Set it up with Windows Eventing
1383 sock
->readEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1384 err
= translate_errno( sock
->readEvent
, GetLastError(), mStatus_UnknownErr
);
1385 require_noerr( err
, exit
);
1386 err
= WSAEventSelect( sock
->sock
, sock
->readEvent
, FD_READ
);
1387 require_noerr( err
, exit
);
1391 sock
->next
= gUDPSocketList
;
1392 gUDPSocketList
= sock
;
1394 gWaitListChanged
= TRUE
;
1402 FreeUDPSocket( sock
);
1410 //===========================================================================================================================
1411 // mDNSPlatformUDPClose
1412 //===========================================================================================================================
1414 mDNSexport
void mDNSPlatformUDPClose( UDPSocket
*sock
)
1416 UDPSocket
* current
= gUDPSocketList
;
1417 UDPSocket
* last
= NULL
;
1421 if ( current
== sock
)
1425 gUDPSocketList
= sock
->next
;
1429 last
->next
= sock
->next
;
1432 FreeUDPSocket( sock
);
1435 gWaitListChanged
= TRUE
;
1441 current
= current
->next
;
1446 //===========================================================================================================================
1447 // mDNSPlatformSendUDP
1448 //===========================================================================================================================
1451 mDNSPlatformSendUDP(
1452 const mDNS
* const inMDNS
,
1453 const void * const inMsg
,
1454 const mDNSu8
* const inMsgEnd
,
1455 mDNSInterfaceID inInterfaceID
,
1456 UDPSocket
* inSrcSocket
,
1457 const mDNSAddr
* inDstIP
,
1458 mDNSIPPort inDstPort
)
1460 SOCKET sendingsocket
= INVALID_SOCKET
;
1461 mStatus err
= mStatus_NoError
;
1462 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
1463 struct sockaddr_storage addr
;
1466 DEBUG_USE_ONLY( inMDNS
);
1468 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
1474 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
1476 if( inDstIP
->type
== mDNSAddrType_IPv4
)
1478 struct sockaddr_in
* sa4
;
1480 sa4
= (struct sockaddr_in
*) &addr
;
1481 sa4
->sin_family
= AF_INET
;
1482 sa4
->sin_port
= inDstPort
.NotAnInteger
;
1483 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
1484 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock4
;
1486 if (inSrcSocket
) { sendingsocket
= inSrcSocket
->sock
; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket
->port
), inMDNS
->p
->unicastSock4
, sendingsocket
); }
1488 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
1490 struct sockaddr_in6
* sa6
;
1492 sa6
= (struct sockaddr_in6
*) &addr
;
1493 sa6
->sin6_family
= AF_INET6
;
1494 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
1495 sa6
->sin6_flowinfo
= 0;
1496 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
1497 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
1498 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock6
;
1502 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
1503 err
= mStatus_BadParamErr
;
1507 if (IsValidSocket(sendingsocket
))
1509 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
1510 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
1514 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1516 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
1518 err
= mStatus_TransientErr
;
1522 require_noerr( err
, exit
);
1532 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1535 DEBUG_UNUSED( InterfaceID
);
1538 //===========================================================================================================================
1539 // mDNSPlatformSendRawPacket
1540 //===========================================================================================================================
1542 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
1544 DEBUG_UNUSED( msg
);
1545 DEBUG_UNUSED( end
);
1546 DEBUG_UNUSED( InterfaceID
);
1549 mDNSexport
void mDNSPlatformReceiveRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
1551 DEBUG_UNUSED( msg
);
1552 DEBUG_UNUSED( end
);
1553 DEBUG_UNUSED( InterfaceID
);
1556 mDNSexport
void mDNSPlatformSetLocalARP( const mDNSv4Addr
* const tpa
, const mDNSEthAddr
* const tha
, mDNSInterfaceID InterfaceID
)
1558 DEBUG_UNUSED( tpa
);
1559 DEBUG_UNUSED( tha
);
1560 DEBUG_UNUSED( InterfaceID
);
1563 mDNSexport
void mDNSPlatformWriteDebugMsg(const char *msg
)
1565 fprintf( stderr
, msg
);
1568 mDNSexport
void mDNSPlatformWriteLogMsg( const char * ident
, const char * msg
, int flags
)
1570 DEBUG_UNUSED( ident
);
1571 DEBUG_UNUSED( msg
);
1572 DEBUG_UNUSED( flags
);
1575 mDNSexport
void mDNSPlatformSourceAddrForDest( mDNSAddr
* const src
, const mDNSAddr
* const dst
)
1577 DEBUG_UNUSED( src
);
1578 DEBUG_UNUSED( dst
);
1581 //===========================================================================================================================
1582 // mDNSPlatformTLSSetupCerts
1583 //===========================================================================================================================
1586 mDNSPlatformTLSSetupCerts(void)
1588 return mStatus_UnsupportedErr
;
1591 //===========================================================================================================================
1592 // mDNSPlatformTLSTearDownCerts
1593 //===========================================================================================================================
1596 mDNSPlatformTLSTearDownCerts(void)
1600 //===========================================================================================================================
1601 // mDNSPlatformSetDNSConfig
1602 //===========================================================================================================================
1604 mDNSlocal
void SetDNSServers( mDNS
*const m
);
1605 mDNSlocal
void SetSearchDomainList( void );
1607 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**regDomains
, DNameListElem
**browseDomains
)
1609 if (setservers
) SetDNSServers(m
);
1610 if (setsearch
) SetSearchDomainList();
1614 GetDDNSFQDN( fqdn
);
1617 if ( browseDomains
)
1619 GetDDNSDomains( browseDomains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
);
1624 GetDDNSDomains( regDomains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
);
1629 //===========================================================================================================================
1630 // mDNSPlatformDynDNSHostNameStatusChanged
1631 //===========================================================================================================================
1634 mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
1636 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1643 ConvertDomainNameToCString(dname
, uname
);
1649 *p
= (char) tolower(*p
);
1650 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1654 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1655 name
= kServiceParametersNode
TEXT("\\DynDNS\\State\\HostNames");
1656 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1657 require_noerr( err
, exit
);
1659 bStatus
= ( status
) ? 0 : 1;
1660 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &bStatus
, sizeof(DWORD
) );
1661 require_noerr( err
, exit
);
1674 //===========================================================================================================================
1676 //===========================================================================================================================
1678 // This routine needs to be called whenever the system secrets database changes.
1679 // We call it from ProcessingThreadDynDNSConfigChanged and mDNSPlatformInit
1682 SetDomainSecrets( mDNS
* const m
)
1684 DomainAuthInfo
*ptr
;
1686 DNameListElem
* regDomains
= NULL
;
1688 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
1689 // In the case where the user simultaneously removes their DDNS host name and the key
1690 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
1691 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
1692 // address records behind that we no longer have permission to delete.
1694 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1695 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
1697 GetDDNSFQDN( &fqdn
);
1701 SetDomainSecret( m
, &fqdn
);
1704 GetDDNSDomains( ®Domains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
);
1706 while ( regDomains
)
1708 DNameListElem
* current
= regDomains
;
1709 SetDomainSecret( m
, ¤t
->name
);
1710 regDomains
= regDomains
->next
;
1716 //===========================================================================================================================
1717 // SetSearchDomainList
1718 //===========================================================================================================================
1720 mDNSlocal
void SetDomainFromDHCP( void );
1721 mDNSlocal
void SetReverseMapSearchDomainList( void );
1724 SetSearchDomainList( void )
1726 char * searchList
= NULL
;
1727 DWORD searchListLen
;
1728 //DNameListElem * head = NULL;
1729 //DNameListElem * current = NULL;
1734 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1735 require_noerr( err
, exit
);
1737 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1738 require_noerr( err
, exit
);
1740 // Windows separates the search domains with ','
1742 tok
= strtok( searchList
, "," );
1745 if ( ( strcmp( tok
, "" ) != 0 ) && ( strcmp( tok
, "." ) != 0 ) )
1746 mDNS_AddSearchDomain_CString(tok
);
1747 tok
= strtok( NULL
, "," );
1762 SetDomainFromDHCP();
1763 SetReverseMapSearchDomainList();
1767 //===========================================================================================================================
1768 // SetReverseMapSearchDomainList
1769 //===========================================================================================================================
1772 SetReverseMapSearchDomainList( void )
1774 struct ifaddrs
* ifa
;
1776 ifa
= myGetIfAddrs( 1 );
1781 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1786 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
1788 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1789 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1790 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1791 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1792 mDNS_AddSearchDomain_CString(buffer
);
1796 ifa
= ifa
->ifa_next
;
1803 //===========================================================================================================================
1805 //===========================================================================================================================
1808 SetDNSServers( mDNS
*const m
)
1810 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1811 FIXED_INFO
* fixedInfo
= NULL
;
1813 IP_ADDR_STRING
* dnsServerList
;
1814 IP_ADDR_STRING
* ipAddr
;
1817 mStatus err
= kUnknownErr
;
1819 // Get the primary interface.
1821 index
= GetPrimaryInterface();
1823 // This should have the interface index of the primary index. Fall back in cases where
1824 // it can't be determined.
1830 for ( i
= 0; i
< 100; i
++ )
1832 err
= GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
);
1834 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1839 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1840 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1843 require_noerr( err
, exit
);
1845 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1849 bufLen
= sizeof( FIXED_INFO
);
1851 for ( i
= 0; i
< 100; i
++ )
1855 GlobalFree( fixedInfo
);
1859 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1860 require_action( fixedInfo
, exit
, err
= mStatus_NoMemoryErr
);
1862 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1864 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1870 require_noerr( err
, exit
);
1872 dnsServerList
= &fixedInfo
->DnsServerList
;
1875 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1878 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1879 if ( !err
) mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
);
1886 free( pAdapterInfo
);
1891 GlobalFree( fixedInfo
);
1896 //===========================================================================================================================
1897 // SetDomainFromDHCP
1898 //===========================================================================================================================
1901 SetDomainFromDHCP( void )
1904 IP_ADAPTER_INFO
* pAdapterInfo
;
1905 IP_ADAPTER_INFO
* pAdapter
;
1909 LPSTR domain
= NULL
;
1911 mStatus err
= mStatus_NoError
;
1913 pAdapterInfo
= NULL
;
1915 for ( i
= 0; i
< 100; i
++ )
1917 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1919 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1924 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
1925 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1928 require_noerr( err
, exit
);
1930 index
= GetPrimaryInterface();
1932 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1934 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1935 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1936 pAdapter
->GatewayList
.IpAddress
.String
&&
1937 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1938 ( !index
|| ( pAdapter
->Index
== index
) ) )
1940 // Found one that will work
1944 _snprintf( keyName
, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter
->AdapterName
);
1946 err
= RegCreateKeyA( HKEY_LOCAL_MACHINE
, keyName
, &key
);
1947 require_noerr( err
, exit
);
1949 err
= RegQueryString( key
, "Domain", &domain
, &dwSize
, NULL
);
1952 if ( !domain
|| !domain
[0] )
1960 err
= RegQueryString( key
, "DhcpDomain", &domain
, &dwSize
, NULL
);
1964 if ( domain
&& domain
[0] ) mDNS_AddSearchDomain_CString(domain
);
1974 free( pAdapterInfo
);
1989 //===========================================================================================================================
1990 // mDNSPlatformGetPrimaryInterface
1991 //===========================================================================================================================
1994 mDNSPlatformGetPrimaryInterface( mDNS
* const m
, mDNSAddr
* v4
, mDNSAddr
* v6
, mDNSAddr
* router
)
1996 IP_ADAPTER_INFO
* pAdapterInfo
;
1997 IP_ADAPTER_INFO
* pAdapter
;
2002 mStatus err
= mStatus_NoError
;
2008 pAdapterInfo
= NULL
;
2012 for ( i
= 0; i
< 100; i
++ )
2014 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2016 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2021 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2022 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2025 require_noerr( err
, exit
);
2027 index
= GetPrimaryInterface();
2029 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2031 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2032 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2033 pAdapter
->GatewayList
.IpAddress
.String
&&
2034 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2035 ( StringToAddress( v4
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
2036 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
2037 ( !index
|| ( pAdapter
->Index
== index
) ) )
2039 // Found one that will work
2050 free( pAdapterInfo
);
2061 //===========================================================================================================================
2063 //===========================================================================================================================
2065 #if( MDNS_DEBUGMSGS )
2066 mDNSexport
void debugf_( const char *inFormat
, ... )
2072 va_start( args
, inFormat
);
2073 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2076 dlog( kDebugLevelInfo
, "%s\n", buffer
);
2080 //===========================================================================================================================
2082 //===========================================================================================================================
2084 #if( MDNS_DEBUGMSGS > 1 )
2085 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
2091 va_start( args
, inFormat
);
2092 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2095 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
2099 //===========================================================================================================================
2101 //===========================================================================================================================
2104 mDNSexport void LogMsg( const char *inFormat, ... )
2110 va_start( args, inFormat );
2111 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2114 dlog( kDebugLevelWarning, "%s\n", buffer );
2120 #pragma mark == Platform Internals ==
2123 //===========================================================================================================================
2124 // SetupSynchronizationObjects
2125 //===========================================================================================================================
2127 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
2131 InitializeCriticalSection( &inMDNS
->p
->lock
);
2132 inMDNS
->p
->lockInitialized
= mDNStrue
;
2134 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2135 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2136 require_noerr( err
, exit
);
2138 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2139 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2140 require_noerr( err
, exit
);
2142 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2143 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2144 require_noerr( err
, exit
);
2146 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2147 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2148 require_noerr( err
, exit
);
2153 TearDownSynchronizationObjects( inMDNS
);
2158 //===========================================================================================================================
2159 // TearDownSynchronizationObjects
2160 //===========================================================================================================================
2162 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
2164 if( inMDNS
->p
->quitEvent
)
2166 CloseHandle( inMDNS
->p
->quitEvent
);
2167 inMDNS
->p
->quitEvent
= 0;
2169 if( inMDNS
->p
->cancelEvent
)
2171 CloseHandle( inMDNS
->p
->cancelEvent
);
2172 inMDNS
->p
->cancelEvent
= 0;
2174 if( inMDNS
->p
->interfaceListChangedEvent
)
2176 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
2177 inMDNS
->p
->interfaceListChangedEvent
= 0;
2179 if( inMDNS
->p
->wakeupEvent
)
2181 CloseHandle( inMDNS
->p
->wakeupEvent
);
2182 inMDNS
->p
->wakeupEvent
= 0;
2184 if( inMDNS
->p
->lockInitialized
)
2186 DeleteCriticalSection( &inMDNS
->p
->lock
);
2187 inMDNS
->p
->lockInitialized
= mDNSfalse
;
2189 return( mStatus_NoError
);
2193 //===========================================================================================================================
2195 //===========================================================================================================================
2197 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
)
2204 // Set up the nice name.
2207 // First try and open the registry key that contains the computer description value
2208 if (inMDNS
->p
->descKey
== NULL
)
2210 LPCTSTR s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2211 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &inMDNS
->p
->descKey
);
2212 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2216 inMDNS
->p
->descKey
= NULL
;
2220 // if we opened it...
2221 if (inMDNS
->p
->descKey
!= NULL
)
2224 DWORD descSize
= sizeof( desc
);
2226 // look for the computer description
2227 err
= RegQueryValueEx(inMDNS
->p
->descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2231 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2240 // if we can't find it in the registry, then use the hostname of the machine
2241 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2243 TCHAR hostname
[256];
2244 DWORD hostnameLen
= sizeof( hostname
) / sizeof( TCHAR
);
2247 ok
= GetComputerNameExW( ComputerNamePhysicalDnsHostname
, hostname
, &hostnameLen
);
2248 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2253 err
= TCHARtoUTF8( hostname
, utf8
, sizeof( utf8
) );
2262 // if we can't get the hostname
2263 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2265 // Invalidate name so fall back to a default name.
2267 strcpy( utf8
, kMDNSDefaultName
);
2270 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2271 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2272 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2274 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2279 //===========================================================================================================================
2281 //===========================================================================================================================
2283 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2286 char tempString
[ 256 ];
2287 DWORD tempStringLen
;
2288 domainlabel tempLabel
;
2293 // Set up the nice name.
2294 tempString
[ 0 ] = '\0';
2296 // use the hostname of the machine
2297 tempStringLen
= sizeof( tempString
);
2298 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2299 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2302 // if we can't get the hostname
2303 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2305 // Invalidate name so fall back to a default name.
2307 strcpy( tempString
, kMDNSDefaultName
);
2310 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2311 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2312 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2314 // Set up the host name.
2316 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2317 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2319 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2321 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2324 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2326 mDNS_SetFQDN( inMDNS
);
2328 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2333 //===========================================================================================================================
2335 //===========================================================================================================================
2337 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2343 err
= SetupNiceName( inMDNS
);
2346 err
= SetupHostName( inMDNS
);
2353 //===========================================================================================================================
2354 // SetupInterfaceList
2355 //===========================================================================================================================
2357 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2360 mDNSInterfaceData
** next
;
2361 mDNSInterfaceData
* ifd
;
2362 struct ifaddrs
* addrs
;
2364 struct ifaddrs
* loopbackv4
;
2365 struct ifaddrs
* loopbackv6
;
2370 mDNSBool foundUnicastSock4DestAddr
;
2371 mDNSBool foundUnicastSock6DestAddr
;
2373 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2377 inMDNS
->p
->registeredLoopback4
= mDNSfalse
;
2378 inMDNS
->p
->nextDHCPLeaseExpires
= 0xFFFFFFFF;
2379 inMDNS
->p
->womp
= mDNSfalse
;
2381 foundv4
= mDNSfalse
;
2382 foundv6
= mDNSfalse
;
2383 foundUnicastSock4DestAddr
= mDNSfalse
;
2384 foundUnicastSock6DestAddr
= mDNSfalse
;
2386 // Tear down any existing interfaces that may be set up.
2388 TearDownInterfaceList( inMDNS
);
2390 // Set up the name of this machine.
2392 err
= SetupName( inMDNS
);
2395 // Set up the interface list change notification.
2397 err
= SetupNotifications( inMDNS
);
2400 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2401 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2403 err
= getifaddrs( &addrs
);
2404 require_noerr( err
, exit
);
2408 next
= &inMDNS
->p
->interfaceList
;
2410 flagMask
= IFF_UP
| IFF_MULTICAST
;
2411 flagTest
= IFF_UP
| IFF_MULTICAST
;
2413 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2414 for( p
= addrs
; p
; p
= p
->ifa_next
)
2416 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2420 if( p
->ifa_flags
& IFF_LOOPBACK
)
2428 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2429 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2431 err
= SetupInterface( inMDNS
, p
, &ifd
);
2432 require_noerr( err
, exit
);
2434 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2435 // register him, but we also want to note that we haven't found a v4 interface
2436 // so that we register loopback so same host operations work
2438 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2443 if ( p
->ifa_dhcpEnabled
&& ( p
->ifa_dhcpLeaseExpires
< inMDNS
->p
->nextDHCPLeaseExpires
) )
2445 inMDNS
->p
->nextDHCPLeaseExpires
= p
->ifa_dhcpLeaseExpires
;
2448 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2449 // of determing the destination address of a packet that is sent to us.
2450 // For multicast packets, that's easy to determine. But for the unicast
2451 // sockets, we'll fake it by taking the address of the first interface
2452 // that is successfully setup.
2454 if ( !foundUnicastSock4DestAddr
)
2456 inMDNS
->p
->unicastSock4DestAddr
= ifd
->interfaceInfo
.ip
;
2457 foundUnicastSock4DestAddr
= TRUE
;
2462 ++inMDNS
->p
->interfaceCount
;
2466 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2468 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2469 for( p
= addrs
; p
; p
= p
->ifa_next
)
2471 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2475 if( p
->ifa_flags
& IFF_LOOPBACK
)
2483 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2484 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2486 err
= SetupInterface( inMDNS
, p
, &ifd
);
2487 require_noerr( err
, exit
);
2489 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2490 // register him, but we also want to note that we haven't found a v4 interface
2491 // so that we register loopback so same host operations work
2493 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2498 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2499 // of determing the destination address of a packet that is sent to us.
2500 // For multicast packets, that's easy to determine. But for the unicast
2501 // sockets, we'll fake it by taking the address of the first interface
2502 // that is successfully setup.
2504 if ( !foundUnicastSock6DestAddr
)
2506 inMDNS
->p
->unicastSock6DestAddr
= ifd
->interfaceInfo
.ip
;
2507 foundUnicastSock6DestAddr
= TRUE
;
2512 ++inMDNS
->p
->interfaceCount
;
2516 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2518 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2520 flagMask
|= IFF_LOOPBACK
;
2521 flagTest
|= IFF_LOOPBACK
;
2523 for( p
= addrs
; p
; p
= p
->ifa_next
)
2525 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2529 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2540 if ( !foundv4
&& loopbackv4
)
2542 dlog( kDebugLevelInfo
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2543 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2545 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2546 require_noerr( err
, exit
);
2548 inMDNS
->p
->registeredLoopback4
= mDNStrue
;
2550 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2552 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2553 // of determing the destination address of a packet that is sent to us.
2554 // For multicast packets, that's easy to determine. But for the unicast
2555 // sockets, we'll fake it by taking the address of the first interface
2556 // that is successfully setup.
2558 if ( !foundUnicastSock4DestAddr
)
2560 inMDNS
->p
->unicastSock4DestAddr
= ifd
->defaultAddr
;
2561 foundUnicastSock4DestAddr
= TRUE
;
2567 ++inMDNS
->p
->interfaceCount
;
2570 if ( !foundv6
&& loopbackv6
)
2572 dlog( kDebugLevelInfo
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2573 loopbackv6
->ifa_name
? loopbackv6
->ifa_name
: "<null>", loopbackv6
->ifa_extra
.index
, loopbackv6
->ifa_addr
);
2575 err
= SetupInterface( inMDNS
, loopbackv6
, &ifd
);
2576 require_noerr( err
, exit
);
2578 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2580 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2581 // of determing the destination address of a packet that is sent to us.
2582 // For multicast packets, that's easy to determine. But for the unicast
2583 // sockets, we'll fake it by taking the address of the first interface
2584 // that is successfully setup.
2586 if ( !foundUnicastSock6DestAddr
)
2588 inMDNS
->p
->unicastSock6DestAddr
= ifd
->defaultAddr
;
2589 foundUnicastSock6DestAddr
= TRUE
;
2595 ++inMDNS
->p
->interfaceCount
;
2601 TearDownInterfaceList( inMDNS
);
2605 freeifaddrs( addrs
);
2607 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2611 //===========================================================================================================================
2612 // TearDownInterfaceList
2613 //===========================================================================================================================
2615 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2618 mDNSInterfaceData
** p
;
2619 mDNSInterfaceData
* ifd
;
2621 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2625 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2626 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2627 // so that remove events that occur after an interface goes away can still report the correct interface.
2629 p
= &inMDNS
->p
->inactiveInterfaceList
;
2633 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2639 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2644 // Tear down interface list change notifications.
2646 err
= TearDownNotifications( inMDNS
);
2649 // Tear down all the interfaces.
2651 while( inMDNS
->p
->interfaceList
)
2653 ifd
= inMDNS
->p
->interfaceList
;
2654 inMDNS
->p
->interfaceList
= ifd
->next
;
2656 TearDownInterface( inMDNS
, ifd
);
2658 inMDNS
->p
->interfaceCount
= 0;
2660 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2661 return( mStatus_NoError
);
2664 //===========================================================================================================================
2666 //===========================================================================================================================
2668 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2670 mDNSInterfaceData
* ifd
;
2671 mDNSInterfaceData
* p
;
2676 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2680 check( inIFA
->ifa_addr
);
2683 // Allocate memory for the interface and initialize it.
2685 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2686 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2687 ifd
->sock
= kInvalidSocketRef
;
2688 ifd
->index
= inIFA
->ifa_extra
.index
;
2689 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2690 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2691 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2692 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2694 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2695 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2697 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2698 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2699 // on a large configured network, which means there's a good chance that most or all the other devices on that
2700 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2701 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2702 // devices on a large configured network, so we are willing to make that sacrifice.
2704 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2705 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2707 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2709 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2711 if (!ifd
->interfaceInfo
.InterfaceID
)
2713 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2716 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2717 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2718 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2720 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2727 if ( !ifd
->interfaceInfo
.InterfaceID
)
2729 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2732 // Set up a socket for this interface (if needed).
2734 if( ifd
->interfaceInfo
.McastTxRx
)
2736 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &sock
);
2737 require_noerr( err
, exit
);
2739 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2741 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2743 #if( !TARGET_OS_WINDOWS_CE )
2747 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
2748 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
2752 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
2757 // Set up the read pending event and associate it so we can block until data is available for this socket.
2759 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2760 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2761 require_noerr( err
, exit
);
2763 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
2764 require_noerr( err
, exit
);
2768 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2770 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2771 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2772 require_noerr( err
, exit
);
2775 if ( inIFA
->ifa_dhcpEnabled
&& ( inIFA
->ifa_dhcpLeaseExpires
< inMDNS
->p
->nextDHCPLeaseExpires
) )
2777 inMDNS
->p
->nextDHCPLeaseExpires
= inIFA
->ifa_dhcpLeaseExpires
;
2780 ifd
->interfaceInfo
.NetWake
= inIFA
->ifa_womp
;
2782 if ( ifd
->interfaceInfo
.NetWake
)
2784 inMDNS
->p
->womp
= TRUE
;
2787 // Register this interface with mDNS.
2789 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2790 require_noerr( err
, exit
);
2792 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2793 require_noerr( err
, exit
);
2795 ifd
->interfaceInfo
.Advertise
= ( mDNSu8
) inMDNS
->AdvertiseLocalAddresses
;
2797 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, mDNSfalse
);
2798 require_noerr( err
, exit
);
2799 ifd
->hostRegistered
= mDNStrue
;
2801 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2812 TearDownInterface( inMDNS
, ifd
);
2814 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2818 //===========================================================================================================================
2819 // TearDownInterface
2820 //===========================================================================================================================
2822 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2829 // Deregister this interface with mDNS.
2831 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2833 if( inIFD
->hostRegistered
)
2835 inIFD
->hostRegistered
= mDNSfalse
;
2836 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
, mDNSfalse
);
2839 // Tear down the multicast socket.
2841 if( inIFD
->readPendingEvent
)
2843 CloseHandle( inIFD
->readPendingEvent
);
2844 inIFD
->readPendingEvent
= 0;
2848 inIFD
->sock
= kInvalidSocketRef
;
2849 if( IsValidSocket( sock
) )
2851 close_compat( sock
);
2854 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2855 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2857 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2859 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2860 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2861 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2865 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2868 return( mStatus_NoError
);
2871 //===========================================================================================================================
2873 //===========================================================================================================================
2875 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2881 DEBUG_UNUSED( inMDNS
);
2883 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2885 check( outSocketRef
);
2887 // Set up an IPv4 or IPv6 UDP socket.
2889 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2890 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2891 require_noerr( err
, exit
);
2893 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2894 // if we're creating a multicast socket
2896 if ( port
.NotAnInteger
)
2899 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2900 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2903 if( inAddr
->sa_family
== AF_INET
)
2906 struct sockaddr_in sa4
;
2907 struct ip_mreq mreqv4
;
2909 // Bind the socket to the desired port
2911 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2912 mDNSPlatformMemZero( &sa4
, sizeof( sa4
) );
2913 sa4
.sin_family
= AF_INET
;
2914 sa4
.sin_port
= port
.NotAnInteger
;
2915 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2917 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2918 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2920 // Turn on option to receive destination addresses and receiving interface.
2923 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2924 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2926 if (port
.NotAnInteger
)
2928 // Join the all-DNS multicast group so we receive Multicast DNS packets
2930 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
2931 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
2932 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
2933 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2935 // Specify the interface to send multicast packets on this socket.
2937 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2938 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
2939 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2941 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2944 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2945 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2948 // Send unicast packets with TTL 255 (helps against spoofing).
2951 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
2952 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2954 // Send multicast packets with TTL 255 (helps against spoofing).
2957 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
2958 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2961 else if( inAddr
->sa_family
== AF_INET6
)
2963 struct sockaddr_in6
* sa6p
;
2964 struct sockaddr_in6 sa6
;
2965 struct ipv6_mreq mreqv6
;
2967 sa6p
= (struct sockaddr_in6
*) inAddr
;
2969 // Bind the socket to the desired port
2971 mDNSPlatformMemZero( &sa6
, sizeof( sa6
) );
2972 sa6
.sin6_family
= AF_INET6
;
2973 sa6
.sin6_port
= port
.NotAnInteger
;
2974 sa6
.sin6_flowinfo
= 0;
2975 sa6
.sin6_addr
= sa6p
->sin6_addr
;
2976 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
2978 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
2979 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2981 // Turn on option to receive destination addresses and receiving interface.
2984 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
2985 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2987 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
2988 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
2989 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
2991 #if( defined( IPV6_V6ONLY ) )
2993 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
2994 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2997 if ( port
.NotAnInteger
)
2999 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3001 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroup_v6
.ip
.v6
);
3002 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
3003 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
3004 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3006 // Specify the interface to send multicast packets on this socket.
3008 option
= (int) sa6p
->sin6_scope_id
;
3009 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
3010 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3012 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3015 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3016 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3019 // Send unicast packets with TTL 255 (helps against spoofing).
3022 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
3023 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3025 // Send multicast packets with TTL 255 (helps against spoofing).
3028 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
3029 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3033 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
3034 err
= kUnsupportedErr
;
3040 *outSocketRef
= sock
;
3041 sock
= kInvalidSocketRef
;
3042 err
= mStatus_NoError
;
3045 if( IsValidSocket( sock
) )
3047 close_compat( sock
);
3052 //===========================================================================================================================
3054 //===========================================================================================================================
3056 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
3063 if( inSA
->sa_family
== AF_INET
)
3065 struct sockaddr_in
* sa4
;
3067 sa4
= (struct sockaddr_in
*) inSA
;
3068 outIP
->type
= mDNSAddrType_IPv4
;
3069 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
3072 outPort
->NotAnInteger
= sa4
->sin_port
;
3074 err
= mStatus_NoError
;
3076 else if( inSA
->sa_family
== AF_INET6
)
3078 struct sockaddr_in6
* sa6
;
3080 sa6
= (struct sockaddr_in6
*) inSA
;
3081 outIP
->type
= mDNSAddrType_IPv6
;
3082 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
3083 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
3085 outIP
->ip
.v6
.w
[ 1 ] = 0;
3089 outPort
->NotAnInteger
= sa6
->sin6_port
;
3091 err
= mStatus_NoError
;
3095 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
3096 err
= mStatus_BadParamErr
;
3101 //===========================================================================================================================
3102 // SetupNotifications
3103 //===========================================================================================================================
3105 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
3109 unsigned long param
;
3114 // Register to listen for address list changes.
3116 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3117 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
3118 require_noerr( err
, exit
);
3119 inMDNS
->p
->interfaceListChangedSocket
= sock
;
3121 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
3122 // when a change to the interface list is detected.
3125 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
3126 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3127 require_noerr( err
, exit
);
3131 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
3134 check( errno_compat() == WSAEWOULDBLOCK
);
3137 err
= WSAEventSelect( sock
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
3138 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3139 require_noerr( err
, exit
);
3141 inMDNS
->p
->descChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
3142 err
= translate_errno( inMDNS
->p
->descChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3143 require_noerr( err
, exit
);
3145 if (inMDNS
->p
->descKey
!= NULL
)
3147 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3148 require_noerr( err
, exit
);
3151 // This will catch all changes to tcp/ip networking, including changes to the domain search list
3153 inMDNS
->p
->tcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3154 err
= translate_errno( inMDNS
->p
->tcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3155 require_noerr( err
, exit
);
3157 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS
->p
->tcpipKey
);
3158 require_noerr( err
, exit
);
3160 err
= RegNotifyChangeKeyValue(inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3161 require_noerr( err
, exit
);
3163 // This will catch all changes to ddns configuration
3165 inMDNS
->p
->ddnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3166 err
= translate_errno( inMDNS
->p
->ddnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3167 require_noerr( err
, exit
);
3169 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &inMDNS
->p
->ddnsKey
);
3170 require_noerr( err
, exit
);
3172 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3173 require_noerr( err
, exit
);
3175 // This will catch all changes to file sharing
3177 inMDNS
->p
->fileShareEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3178 err
= translate_errno( inMDNS
->p
->fileShareEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3179 require_noerr( err
, exit
);
3181 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &inMDNS
->p
->fileShareKey
);
3182 require_noerr( err
, exit
);
3184 err
= RegNotifyChangeKeyValue(inMDNS
->p
->fileShareKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->fileShareEvent
, TRUE
);
3185 require_noerr( err
, exit
);
3187 // This will catch changes to the Windows firewall
3189 inMDNS
->p
->firewallEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3190 err
= translate_errno( inMDNS
->p
->firewallEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3191 require_noerr( err
, exit
);
3193 // Just to make sure that initialization doesn't fail on some old OS
3194 // that doesn't have this key, we'll only add the notification if
3197 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &inMDNS
->p
->firewallKey
);
3201 err
= RegNotifyChangeKeyValue(inMDNS
->p
->firewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->firewallEvent
, TRUE
);
3202 require_noerr( err
, exit
);
3206 err
= mStatus_NoError
;
3212 TearDownNotifications( inMDNS
);
3217 //===========================================================================================================================
3218 // TearDownNotifications
3219 //===========================================================================================================================
3221 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
3223 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
3225 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
3226 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
3229 if ( inMDNS
->p
->descChangedEvent
!= NULL
)
3231 CloseHandle( inMDNS
->p
->descChangedEvent
);
3232 inMDNS
->p
->descChangedEvent
= NULL
;
3235 if ( inMDNS
->p
->descKey
!= NULL
)
3237 RegCloseKey( inMDNS
->p
->descKey
);
3238 inMDNS
->p
->descKey
= NULL
;
3241 if ( inMDNS
->p
->tcpipChangedEvent
!= NULL
)
3243 CloseHandle( inMDNS
->p
->tcpipChangedEvent
);
3244 inMDNS
->p
->tcpipChangedEvent
= NULL
;
3247 if ( inMDNS
->p
->ddnsChangedEvent
!= NULL
)
3249 CloseHandle( inMDNS
->p
->ddnsChangedEvent
);
3250 inMDNS
->p
->ddnsChangedEvent
= NULL
;
3253 if ( inMDNS
->p
->ddnsKey
!= NULL
)
3255 RegCloseKey( inMDNS
->p
->ddnsKey
);
3256 inMDNS
->p
->ddnsKey
= NULL
;
3259 if ( inMDNS
->p
->fileShareEvent
!= NULL
)
3261 CloseHandle( inMDNS
->p
->fileShareEvent
);
3262 inMDNS
->p
->fileShareEvent
= NULL
;
3265 if ( inMDNS
->p
->fileShareKey
!= NULL
)
3267 RegCloseKey( inMDNS
->p
->fileShareKey
);
3268 inMDNS
->p
->fileShareKey
= NULL
;
3271 if ( inMDNS
->p
->firewallEvent
!= NULL
)
3273 CloseHandle( inMDNS
->p
->firewallEvent
);
3274 inMDNS
->p
->firewallEvent
= NULL
;
3277 if ( inMDNS
->p
->firewallKey
!= NULL
)
3279 RegCloseKey( inMDNS
->p
->firewallKey
);
3280 inMDNS
->p
->firewallKey
= NULL
;
3283 return( mStatus_NoError
);
3291 //===========================================================================================================================
3293 //===========================================================================================================================
3295 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
3298 HANDLE threadHandle
;
3302 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
3304 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3305 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3307 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3308 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3309 require_noerr( err
, exit
);
3311 inMDNS
->p
->initStatus
= mStatus_Invalid
;
3313 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3314 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3316 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
3317 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
3318 require_noerr( err
, exit
);
3320 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
3321 err
= translate_errno( result
== WAIT_OBJECT_0
, (mStatus
) GetLastError(), kUnknownErr
);
3322 require_noerr( err
, exit
);
3323 err
= inMDNS
->p
->initStatus
;
3324 require_noerr( err
, exit
);
3327 if( inMDNS
->p
->initEvent
)
3329 CloseHandle( inMDNS
->p
->initEvent
);
3330 inMDNS
->p
->initEvent
= 0;
3332 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
3336 //===========================================================================================================================
3338 //===========================================================================================================================
3340 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
3342 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3343 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3345 if( inMDNS
->p
->cancelEvent
)
3350 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
3351 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3353 if( inMDNS
->p
->quitEvent
)
3355 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
3356 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
3359 return( mStatus_NoError
);
3362 //===========================================================================================================================
3364 //===========================================================================================================================
3366 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
3378 m
= (mDNS
*) inParam
;
3379 err
= ProcessingThreadInitialize( m
);
3385 // Set up the list of objects we'll be waiting on.
3389 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
3390 require_noerr( err
, exit
);
3392 // Main processing loop.
3394 gWaitListChanged
= FALSE
;
3398 // Give the mDNS core a chance to do its work and determine next event time.
3400 mDNSs32 interval
= mDNS_Execute(m
) - mDNS_TimeNow(m
);
3402 if ( gWaitListChanged
)
3407 if (m
->p
->idleThreadCallback
)
3409 interval
= m
->p
->idleThreadCallback(m
, interval
);
3411 if (interval
< 0) interval
= 0;
3412 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
3413 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
3415 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3417 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
3418 check( result
!= WAIT_FAILED
);
3420 if ( result
!= WAIT_FAILED
)
3422 if( result
== WAIT_TIMEOUT
)
3424 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3426 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
3429 else if( result
== kWaitListCancelEvent
)
3431 // Cancel event. Set the done flag and break to exit.
3433 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
3437 else if( result
== kWaitListInterfaceListChangedEvent
)
3439 // It would be nice to come up with a more elegant solution to this, but it seems that
3440 // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as
3441 // as a simple workaround, we'll pause for a couple of seconds before processing the change.
3443 // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
3444 // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another
3445 // second on top of that to account for machine load or some other exigency.
3449 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3451 ProcessingThreadInterfaceListChanged( m
);
3454 else if( result
== kWaitListWakeupEvent
)
3456 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3458 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
3461 else if ( result
== kWaitListComputerDescriptionEvent
)
3464 // The computer description might have changed
3466 ProcessingThreadComputerDescriptionChanged( m
);
3469 else if ( result
== kWaitListTCPIPEvent
)
3472 // The TCP/IP might have changed
3474 ProcessingThreadTCPIPConfigChanged( m
);
3477 else if ( result
== kWaitListDynDNSEvent
)
3480 // The DynDNS config might have changed
3482 ProcessingThreadDynDNSConfigChanged( m
);
3485 else if ( result
== kWaitListFileShareEvent
)
3488 // File sharing changed
3490 ProcessingThreadFileShareChanged( m
);
3493 else if ( result
== kWaitListFirewallEvent
)
3496 // Firewall configuration changed
3498 ProcessingThreadFirewallChanged( m
);
3504 // Socket data available event. Determine which socket and process the packet.
3506 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
3507 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
3508 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
3510 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
3512 HANDLE signaledObject
;
3514 mDNSInterfaceData
* ifd
;
3518 signaledObject
= waitList
[ waitItemIndex
];
3520 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3521 if ( m
->p
->unicastSock4ReadEvent
== signaledObject
)
3523 ProcessingThreadProcessPacket( m
, NULL
, NULL
, m
->p
->unicastSock4
);
3528 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3529 if ( m
->p
->unicastSock6ReadEvent
== signaledObject
)
3531 ProcessingThreadProcessPacket( m
, NULL
, NULL
, m
->p
->unicastSock6
);
3536 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3538 if( ifd
->readPendingEvent
== signaledObject
)
3540 ProcessingThreadProcessPacket( m
, ifd
, NULL
, ifd
->sock
);
3545 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3547 if ( tcd
->pendingEvent
== signaledObject
)
3549 mDNSBool connect
= FALSE
;
3551 if ( !tcd
->connected
)
3553 tcd
->connected
= mDNStrue
;
3557 tcd
->callback( tcd
, tcd
->context
, connect
, 0 );
3565 for ( sock
= gUDPSocketList
; sock
; sock
= sock
->next
)
3567 if ( sock
->readEvent
== signaledObject
)
3569 ProcessingThreadProcessPacket( m
, NULL
, sock
, sock
->sock
);
3581 // Unexpected wait result.
3583 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
3590 err
= ProcessingThreadInitialize( m
);
3596 // Release the wait list.
3606 // Signal the quit event to indicate that the thread is finished.
3609 wasSet
= SetEvent( m
->p
->quitEvent
);
3610 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3612 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3613 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3615 _endthreadex_compat( 0 );
3619 //===========================================================================================================================
3620 // ProcessingThreadInitialize
3621 //===========================================================================================================================
3623 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
3628 inMDNS
->p
->threadID
= GetCurrentThreadId();
3630 err
= SetupInterfaceList( inMDNS
);
3631 require_noerr( err
, exit
);
3633 err
= uDNS_SetupDNSConfig( inMDNS
);
3634 require_noerr( err
, exit
);
3640 TearDownInterfaceList( inMDNS
);
3642 inMDNS
->p
->initStatus
= err
;
3644 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
3645 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3649 //===========================================================================================================================
3650 // ProcessingThreadSetupWaitList
3651 //===========================================================================================================================
3653 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
3658 HANDLE
* waitItemPtr
;
3659 mDNSInterfaceData
* ifd
;
3663 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
3666 check( outWaitList
);
3667 check( outWaitListCount
);
3669 // Allocate an array to hold all the objects to wait on.
3671 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->interfaceCount
+ gTCPConnections
+ gUDPSockets
;
3672 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
3673 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
3674 waitItemPtr
= waitList
;
3676 // Add the fixed wait items to the beginning of the list.
3678 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
3679 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
3680 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
3681 *waitItemPtr
++ = inMDNS
->p
->descChangedEvent
;
3682 *waitItemPtr
++ = inMDNS
->p
->tcpipChangedEvent
;
3683 *waitItemPtr
++ = inMDNS
->p
->ddnsChangedEvent
;
3684 *waitItemPtr
++ = inMDNS
->p
->fileShareEvent
;
3685 *waitItemPtr
++ = inMDNS
->p
->firewallEvent
;
3687 // Append all the dynamic wait items to the list.
3688 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3689 *waitItemPtr
++ = inMDNS
->p
->unicastSock4ReadEvent
;
3692 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3693 *waitItemPtr
++ = inMDNS
->p
->unicastSock6ReadEvent
;
3696 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3698 *waitItemPtr
++ = ifd
->readPendingEvent
;
3701 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3703 *waitItemPtr
++ = tcd
->pendingEvent
;
3706 for ( sock
= gUDPSocketList
; sock
; sock
= sock
->next
)
3708 *waitItemPtr
++ = sock
->readEvent
;
3711 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
3713 *outWaitList
= waitList
;
3714 *outWaitListCount
= waitListCount
;
3716 err
= mStatus_NoError
;
3723 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
3727 //===========================================================================================================================
3728 // ProcessingThreadProcessPacket
3729 //===========================================================================================================================
3731 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, UDPSocket
* inUDPSocket
, SocketRef inSock
)
3734 const mDNSInterfaceID iid
= inIFD
? inIFD
->interfaceInfo
.InterfaceID
: NULL
;
3735 LPFN_WSARECVMSG recvMsgPtr
;
3741 struct sockaddr_storage addr
;
3747 check( IsValidSocket( inSock
) );
3749 // Set up the default in case the packet info options are not supported or reported correctly.
3753 recvMsgPtr
= inIFD
->wsaRecvMsgFunctionPtr
;
3754 dstAddr
= inIFD
->defaultAddr
;
3755 dstPort
= MulticastDNSPort
;
3758 else if ( inUDPSocket
)
3760 recvMsgPtr
= inUDPSocket
->recvMsgPtr
;
3761 dstAddr
= inUDPSocket
->dstAddr
;
3762 dstPort
= inUDPSocket
->port
;
3765 else if ( inSock
== inMDNS
->p
->unicastSock4
)
3767 recvMsgPtr
= inMDNS
->p
->unicastSock4RecvMsgPtr
;
3768 dstAddr
= inMDNS
->p
->unicastSock4DestAddr
;
3769 dstPort
= inMDNS
->UnicastPort4
;
3772 else if ( inSock
== inMDNS
->p
->unicastSock6
)
3774 recvMsgPtr
= inMDNS
->p
->unicastSock6RecvMsgPtr
;
3775 dstAddr
= inMDNS
->p
->unicastSock6DestAddr
;
3776 dstPort
= inMDNS
->UnicastPort6
;
3781 dlog( kDebugLevelError
, DEBUG_NAME
"packet received on unknown socket\n" );
3785 #if( !TARGET_OS_WINDOWS_CE )
3790 uint8_t controlBuffer
[ 128 ];
3792 LPWSACMSGHDR header
;
3794 // Set up the buffer and read the packet.
3796 msg
.name
= (LPSOCKADDR
) &addr
;
3797 msg
.namelen
= (INT
) sizeof( addr
);
3798 buf
.buf
= (char *) &packet
;
3799 buf
.len
= (u_long
) sizeof( packet
);
3800 msg
.lpBuffers
= &buf
;
3801 msg
.dwBufferCount
= 1;
3802 msg
.Control
.buf
= (char *) controlBuffer
;
3803 msg
.Control
.len
= (u_long
) sizeof( controlBuffer
);
3806 err
= recvMsgPtr( inSock
, &msg
, &size
, NULL
, NULL
);
3807 err
= translate_errno( err
== 0, (OSStatus
) WSAGetLastError(), kUnknownErr
);
3808 require_noerr( err
, exit
);
3811 // Parse the control information. Reject packets received on the wrong interface.
3813 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
3815 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3817 IN_PKTINFO
* ipv4PacketInfo
;
3819 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3823 require_action( ipv4PacketInfo
->ipi_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
3826 dstAddr
.type
= mDNSAddrType_IPv4
;
3827 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3829 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3831 IN6_PKTINFO
* ipv6PacketInfo
;
3833 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3837 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( inIFD
->index
- kIPv6IfIndexBase
), exit
, err
= kMismatchErr
);
3840 dstAddr
.type
= mDNSAddrType_IPv6
;
3841 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3850 addrSize
= sizeof( addr
);
3851 n
= recvfrom( inSock
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
3852 err
= translate_errno( n
> 0, errno_compat(), kUnknownErr
);
3853 require_noerr( err
, exit
);
3855 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
3857 // Dispatch the packet to mDNS.
3859 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3860 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
3861 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3862 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3866 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &inIFD
->interfaceInfo
.ip
, (int) inIFD
->index
);
3869 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3871 end
= ( (mDNSu8
*) &packet
) + n
;
3872 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3878 //===========================================================================================================================
3879 // ProcessingThreadInterfaceListChanged
3880 //===========================================================================================================================
3882 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
3886 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3889 if (inMDNS
->p
->interfaceListChangedCallback
)
3891 inMDNS
->p
->interfaceListChangedCallback(inMDNS
);
3894 mDNSPlatformLock( inMDNS
);
3896 // Tear down the existing interfaces and set up new ones using the new IP info.
3898 err
= TearDownInterfaceList( inMDNS
);
3901 err
= SetupInterfaceList( inMDNS
);
3904 err
= uDNS_SetupDNSConfig( inMDNS
);
3907 mDNSPlatformUnlock( inMDNS
);
3909 // Inform clients of the change.
3911 mDNS_ConfigChanged(inMDNS
);
3913 // Force mDNS to update.
3915 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
); // What is this for? Mac OS X does not do this
3919 //===========================================================================================================================
3920 // ProcessingThreadComputerDescriptionChanged
3921 //===========================================================================================================================
3922 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
*inMDNS
)
3926 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3929 mDNSPlatformLock( inMDNS
);
3932 SetupNiceName( inMDNS
);
3934 if (inMDNS
->p
->hostDescriptionChangedCallback
)
3936 inMDNS
->p
->hostDescriptionChangedCallback(inMDNS
);
3939 // and reset the event handler
3940 if ((inMDNS
->p
->descKey
!= NULL
) && (inMDNS
->p
->descChangedEvent
))
3942 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3946 mDNSPlatformUnlock( inMDNS
);
3950 //===========================================================================================================================
3951 // ProcessingThreadTCPIPConfigChanged
3952 //===========================================================================================================================
3953 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
)
3957 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3960 mDNSPlatformLock( inMDNS
);
3962 err
= uDNS_SetupDNSConfig( inMDNS
);
3965 // and reset the event handler
3967 if ( ( inMDNS
->p
->tcpipKey
!= NULL
) && ( inMDNS
->p
->tcpipChangedEvent
) )
3969 err
= RegNotifyChangeKeyValue( inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3973 mDNSPlatformUnlock( inMDNS
);
3977 //===========================================================================================================================
3978 // ProcessingThreadDynDNSConfigChanged
3979 //===========================================================================================================================
3980 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
*inMDNS
)
3984 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3987 SetDomainSecrets( inMDNS
);
3989 mDNSPlatformLock( inMDNS
);
3991 err
= uDNS_SetupDNSConfig( inMDNS
);
3994 // and reset the event handler
3996 if ((inMDNS
->p
->ddnsKey
!= NULL
) && (inMDNS
->p
->ddnsChangedEvent
))
3998 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
4002 mDNSPlatformUnlock( inMDNS
);
4006 //===========================================================================================================================
4007 // ProcessingThreadFileShareChanged
4008 //===========================================================================================================================
4009 mDNSlocal
void ProcessingThreadFileShareChanged( mDNS
*inMDNS
)
4013 dlog( kDebugLevelInfo
, DEBUG_NAME
"File shares has changed\n" );
4016 CheckFileShares( inMDNS
);
4018 // and reset the event handler
4020 if ((inMDNS
->p
->fileShareKey
!= NULL
) && (inMDNS
->p
->fileShareEvent
))
4022 err
= RegNotifyChangeKeyValue(inMDNS
->p
->fileShareKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->fileShareEvent
, TRUE
);
4028 //===========================================================================================================================
4029 // ProcessingThreadFileShareChanged
4030 //===========================================================================================================================
4031 mDNSlocal
void ProcessingThreadFirewallChanged( mDNS
*inMDNS
)
4035 dlog( kDebugLevelInfo
, DEBUG_NAME
"Firewall has changed\n" );
4038 CheckFileShares( inMDNS
);
4040 // and reset the event handler
4042 if ((inMDNS
->p
->firewallKey
!= NULL
) && (inMDNS
->p
->firewallEvent
))
4044 err
= RegNotifyChangeKeyValue(inMDNS
->p
->firewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->firewallEvent
, TRUE
);
4053 #pragma mark == Utilities ==
4056 //===========================================================================================================================
4058 //===========================================================================================================================
4060 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
)
4064 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
4066 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
4067 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
4069 if( !gIPHelperLibraryInstance
)
4071 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
4072 if( gIPHelperLibraryInstance
)
4074 gGetAdaptersAddressesFunctionPtr
=
4075 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
4076 if( !gGetAdaptersAddressesFunctionPtr
)
4080 ok
= FreeLibrary( gIPHelperLibraryInstance
);
4081 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
4082 gIPHelperLibraryInstance
= NULL
;
4087 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
4088 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
4089 // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
4091 if( !gGetAdaptersAddressesFunctionPtr
|| ( ( ( err
= getifaddrs_ipv6( outAddrs
) ) != mStatus_NoError
) || ( ( outAddrs
!= NULL
) && ( *outAddrs
== NULL
) ) ) )
4093 err
= getifaddrs_ipv4( outAddrs
);
4094 require_noerr( err
, exit
);
4097 #elif( !TARGET_OS_WINDOWS_CE )
4099 err
= getifaddrs_ipv4( outAddrs
);
4100 require_noerr( err
, exit
);
4104 err
= getifaddrs_ce( outAddrs
);
4105 require_noerr( err
, exit
);
4113 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
4114 //===========================================================================================================================
4116 //===========================================================================================================================
4118 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
4123 struct ifaddrs
* head
;
4124 struct ifaddrs
** next
;
4125 IP_ADAPTER_ADDRESSES
* iaaList
;
4127 IP_ADAPTER_ADDRESSES
* iaa
;
4129 struct ifaddrs
* ifa
;
4131 check( gGetAdaptersAddressesFunctionPtr
);
4137 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
4138 // This loops to handle the case where the interface changes in the window after getting the size, but before the
4139 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
4141 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
4146 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
4147 check( err
== ERROR_BUFFER_OVERFLOW
);
4148 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
4150 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
4151 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
4153 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
4154 if( err
== ERROR_SUCCESS
) break;
4159 require( i
< 100, exit
);
4160 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
4163 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
4166 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
4168 IP_ADAPTER_PREFIX
* firstPrefix
;
4170 if( iaa
->IfIndex
> 0xFFFFFF )
4172 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
4174 if( iaa
->Ipv6IfIndex
> 0xFF )
4176 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
4179 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
4180 // following code to crash when iterating through the prefix list. This seems
4181 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
4182 // This shouldn't happen according to Microsoft docs which states:
4184 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
4186 // So the data structure seems to be corrupted when we return from
4187 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
4188 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
4189 // modify iaa to have the correct values.
4191 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
4193 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
4194 firstPrefix
= iaa
->FirstPrefix
;
4202 // Skip pseudo and tunnel interfaces.
4204 if( ( ( ipv6IfIndex
== 1 ) && ( iaa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
) ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
4209 // Add each address as a separate interface to emulate the way getifaddrs works.
4211 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
4215 IP_ADAPTER_PREFIX
* prefix
;
4218 struct sockaddr_in ipv4Netmask
;
4220 family
= addr
->Address
.lpSockaddr
->sa_family
;
4221 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
4223 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
4224 // Seems as if the problem here is a buggy implementation of some network interface
4225 // driver. It is reporting that is has a link-local address when it is actually
4226 // disconnected. This was causing a problem in AddressToIndexAndMask.
4227 // The solution is to call AddressToIndexAndMask first, and if unable to lookup
4228 // the address, to ignore that address.
4231 memset( &ipv4Netmask
, 0, sizeof( ipv4Netmask
) );
4233 if ( family
== AF_INET
)
4235 err
= AddressToIndexAndMask( addr
->Address
.lpSockaddr
, &ipv4Index
, ( struct sockaddr
* ) &ipv4Netmask
);
4244 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4245 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4248 next
= &ifa
->ifa_next
;
4252 size
= strlen( iaa
->AdapterName
) + 1;
4253 ifa
->ifa_name
= (char *) malloc( size
);
4254 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4255 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
4257 // Get interface flags.
4260 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
4261 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
4262 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
4263 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
4266 // <rdar://problem/4045657> Interface index being returned is 512
4268 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
4269 // This code used to shift the IPv4 index up to ensure uniqueness between
4270 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
4271 // then see interface indexes passed back that don't correspond to anything
4272 // that is seen in Win32 APIs or command line tools like "route". As a relatively
4273 // small percentage of developers are actively using IPv6, it seems to
4274 // make sense to make our use of IPv4 as confusion free as possible.
4275 // So now, IPv6 interface indexes will be shifted up by a
4276 // constant value which will serve to uniquely identify them, and we will
4277 // leave IPv4 interface indexes unmodified.
4281 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
4282 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
4286 // Get lease lifetime
4288 if ( ( iaa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
) && ( addr
->LeaseLifetime
!= 0 ) && ( addr
->LeaseLifetime
!= 0xFFFFFFFF ) )
4290 ifa
->ifa_dhcpEnabled
= TRUE
;
4291 ifa
->ifa_dhcpLeaseExpires
= time( NULL
) + addr
->LeaseLifetime
;
4295 ifa
->ifa_dhcpEnabled
= FALSE
;
4296 ifa
->ifa_dhcpLeaseExpires
= 0;
4299 // Get WakeOnLAN settings
4301 if ( iaa
->IfType
== IF_TYPE_ETHERNET_CSMACD
)
4303 ifa
->ifa_womp
= IsWOMPEnabled( iaa
->AdapterName
);
4312 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
4313 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4314 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
4320 check( ifa
->ifa_addr
);
4322 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
4325 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
4327 if( ( prefix
->Address
.lpSockaddr
->sa_family
== family
) && ( prefixIndex
== addrIndex
) )
4329 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
4330 prefixLength
= prefix
->PrefixLength
;
4338 struct sockaddr_in
* sa4
;
4340 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
4341 require_action( sa4
, exit
, err
= WSAENOBUFS
);
4342 sa4
->sin_family
= AF_INET
;
4343 sa4
->sin_addr
.s_addr
= ipv4Netmask
.sin_addr
.s_addr
;
4345 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
4346 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
4352 struct sockaddr_in6
* sa6
;
4357 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
4359 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
4360 require_action( sa6
, exit
, err
= WSAENOBUFS
);
4361 sa6
->sin6_family
= AF_INET6
;
4363 if( prefixLength
== 0 )
4365 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
4369 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
4371 if( len
>= 8 ) maskByte
= 0xFF;
4372 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
4373 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
4375 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
4392 err
= ERROR_SUCCESS
;
4397 freeifaddrs( head
);
4403 return( (int) err
);
4406 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
4408 #if( !TARGET_OS_WINDOWS_CE )
4409 //===========================================================================================================================
4411 //===========================================================================================================================
4413 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
4419 INTERFACE_INFO
* buffer
;
4420 INTERFACE_INFO
* tempBuffer
;
4421 INTERFACE_INFO
* ifInfo
;
4422 IP_ADAPTER_INFO
* pAdapterInfo
;
4423 IP_ADAPTER_INFO
* pAdapter
;
4427 struct ifaddrs
* head
;
4428 struct ifaddrs
** next
;
4429 struct ifaddrs
* ifa
;
4431 sock
= INVALID_SOCKET
;
4435 pAdapterInfo
= NULL
;
4437 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4438 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4439 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4441 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4442 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4443 require_noerr( err
, exit
);
4446 size
= 16 * sizeof( INTERFACE_INFO
);
4449 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
4450 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
4451 buffer
= tempBuffer
;
4453 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
4460 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
4462 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
4464 check( actualSize
<= size
);
4465 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
4466 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
4468 // Now call GetAdaptersInfo so we can get DHCP information for each interface
4470 pAdapterInfo
= NULL
;
4473 for ( i
= 0; i
< 100; i
++ )
4475 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
4477 if ( err
!= ERROR_BUFFER_OVERFLOW
)
4482 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
4484 if ( !pAdapterInfo
)
4490 // Process the raw interface list and build a linked list of IPv4 interfaces.
4492 for( i
= 0; i
< n
; ++i
)
4495 struct sockaddr_in netmask
;
4497 ifInfo
= &buffer
[ i
];
4498 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
4503 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
4504 // See comment in getifaddrs_ipv6
4507 memset( &netmask
, 0, sizeof( netmask
) );
4508 err
= AddressToIndexAndMask( ( struct sockaddr
* ) &ifInfo
->iiAddress
.AddressIn
, &ifIndex
, ( struct sockaddr
* ) &netmask
);
4515 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4516 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4519 next
= &ifa
->ifa_next
;
4523 ifa
->ifa_name
= (char *) malloc( 16 );
4524 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4525 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4527 // Get interface flags.
4529 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4533 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
4535 struct sockaddr_in
* sa4
;
4537 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4538 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4539 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4540 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4542 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4543 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4545 // <rdar://problem/4076478> Service won't start on Win2K. The address
4546 // family field was not being initialized.
4548 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4549 ( ( struct sockaddr_in
* ) ifa
->ifa_netmask
)->sin_addr
= netmask
.sin_addr
;
4550 ifa
->ifa_extra
.index
= ifIndex
;
4554 // Emulate an interface index.
4556 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4559 // Now get DHCP configuration information
4561 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
4563 if ( strcmp( inet_ntoa( ifInfo
->iiAddress
.AddressIn
.sin_addr
), pAdapter
->IpAddressList
.IpAddress
.String
) == 0 )
4565 ifa
->ifa_dhcpEnabled
= pAdapter
->DhcpEnabled
;
4566 ifa
->ifa_dhcpLeaseExpires
= pAdapter
->LeaseExpires
;
4567 ifa
->ifa_womp
= IsWOMPEnabled( pAdapter
->AdapterName
);
4586 free( pAdapterInfo
);
4590 freeifaddrs( head
);
4596 if( sock
!= INVALID_SOCKET
)
4598 closesocket( sock
);
4602 #endif // !TARGET_OS_WINDOWS_CE )
4604 #if( TARGET_OS_WINDOWS_CE )
4605 //===========================================================================================================================
4607 //===========================================================================================================================
4609 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
4615 SOCKET_ADDRESS_LIST
* addressList
;
4616 struct ifaddrs
* head
;
4617 struct ifaddrs
** next
;
4618 struct ifaddrs
* ifa
;
4622 sock
= kInvalidSocketRef
;
4627 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4629 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4630 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4631 require_noerr( err
, exit
);
4633 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4634 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4636 // Note: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4639 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
4640 require_action( size
> 0, exit
, err
= -1 );
4643 buffer
= calloc( 1, size
);
4644 require_action( buffer
, exit
, err
= -1 );
4646 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4648 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
4649 require_noerr( err
, exit
);
4650 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
4652 // Process the raw interface list and build a linked list of interfaces.
4654 // Note: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4656 n
= addressList
->iAddressCount
;
4661 for( i
= 0; i
< n
; ++i
)
4663 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4664 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4667 next
= &ifa
->ifa_next
;
4671 ifa
->ifa_name
= (char *) malloc( 16 );
4672 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4673 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4675 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4677 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
4681 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
4685 struct sockaddr_in
* sa4
;
4687 sa4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
4688 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4689 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4690 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4711 freeifaddrs( head
);
4717 if( sock
!= INVALID_SOCKET
)
4719 closesocket( sock
);
4723 #endif // TARGET_OS_WINDOWS_CE )
4725 //===========================================================================================================================
4727 //===========================================================================================================================
4729 mDNSlocal
void freeifaddrs( struct ifaddrs
*inIFAs
)
4734 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4736 for( p
= inIFAs
; p
; p
= q
)
4742 free( p
->ifa_name
);
4747 free( p
->ifa_addr
);
4750 if( p
->ifa_netmask
)
4752 free( p
->ifa_netmask
);
4753 p
->ifa_netmask
= NULL
;
4755 if( p
->ifa_broadaddr
)
4757 free( p
->ifa_broadaddr
);
4758 p
->ifa_broadaddr
= NULL
;
4760 if( p
->ifa_dstaddr
)
4762 free( p
->ifa_dstaddr
);
4763 p
->ifa_dstaddr
= NULL
;
4767 free( p
->ifa_data
);
4775 //===========================================================================================================================
4776 // GetPrimaryInterface
4777 //===========================================================================================================================
4780 GetPrimaryInterface()
4782 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4784 BOOL bOrder
= FALSE
;
4788 unsigned long int i
;
4790 // Find out how big our buffer needs to be.
4792 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4793 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4795 // Allocate the memory for the table
4797 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4798 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4800 // Now get the table.
4802 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4803 require_noerr( err
, exit
);
4806 // Search for the row in the table we want.
4808 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4810 // Look for a default route
4812 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4814 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4819 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4820 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4826 if ( pIpForwardTable
!= NULL
)
4828 free( pIpForwardTable
);
4835 //===========================================================================================================================
4836 // AddressToIndexAndMask
4837 //===========================================================================================================================
4840 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4842 // Before calling AddIPAddress we use GetIpAddrTable to get
4843 // an adapter to which we can add the IP.
4845 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4847 mStatus err
= mStatus_UnknownErr
;
4850 // For now, this is only for IPv4 addresses. That is why we can safely cast
4851 // addr's to sockaddr_in.
4853 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4855 // Make an initial call to GetIpAddrTable to get the
4856 // necessary size into the dwSize variable
4858 for ( i
= 0; i
< 100; i
++ )
4860 err
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
4862 if ( err
!= ERROR_INSUFFICIENT_BUFFER
)
4867 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4868 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4871 require_noerr( err
, exit
);
4872 err
= mStatus_UnknownErr
;
4874 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4876 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4878 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4879 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4880 err
= mStatus_NoError
;
4889 free( pIPAddrTable
);
4896 //===========================================================================================================================
4897 // CanReceiveUnicast
4898 //===========================================================================================================================
4900 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4904 struct sockaddr_in addr
;
4906 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4908 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4909 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4910 ok
= IsValidSocket( sock
);
4913 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
4914 addr
.sin_family
= AF_INET
;
4915 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4916 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4918 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4919 close_compat( sock
);
4922 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4927 //===========================================================================================================================
4929 //===========================================================================================================================
4931 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4933 struct ifaddrs
* addrs
= NULL
;
4934 struct ifaddrs
* p
= NULL
;
4936 mDNSBool ret
= mDNSfalse
;
4938 // For now, only works for IPv4 interfaces
4940 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4942 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4944 err
= getifaddrs_ipv4( &addrs
);
4945 require_noerr( err
, exit
);
4947 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4949 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4950 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4952 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4962 freeifaddrs( addrs
);
4969 //===========================================================================================================================
4970 // GetWindowsVersionString
4971 //===========================================================================================================================
4973 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4975 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4976 #define VER_PLATFORM_WIN32_CE 3
4980 OSVERSIONINFO osInfo
;
4982 const char * versionString
;
4988 versionString
= "unknown Windows version";
4990 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4991 ok
= GetVersionEx( &osInfo
);
4992 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4993 require_noerr( err
, exit
);
4995 platformID
= osInfo
.dwPlatformId
;
4996 majorVersion
= osInfo
.dwMajorVersion
;
4997 minorVersion
= osInfo
.dwMinorVersion
;
4998 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
5000 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
5002 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
5004 versionString
= "Windows 95";
5006 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
5008 versionString
= "Windows 95 SP1";
5010 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
5012 versionString
= "Windows 95 OSR2";
5014 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
5016 versionString
= "Windows 98";
5018 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
5020 versionString
= "Windows 98 SP1";
5022 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
5024 versionString
= "Windows 98 SE";
5026 else if( minorVersion
== 90 )
5028 versionString
= "Windows ME";
5031 else if( platformID
== VER_PLATFORM_WIN32_NT
)
5033 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
5035 versionString
= "Windows NT 3.51";
5037 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
5039 versionString
= "Windows NT 4";
5041 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
5043 versionString
= "Windows 2000";
5045 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
5047 versionString
= "Windows XP";
5049 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
5051 versionString
= "Windows Server 2003";
5054 else if( platformID
== VER_PLATFORM_WIN32_CE
)
5056 versionString
= "Windows CE";
5060 if( inBuffer
&& ( inBufferSize
> 0 ) )
5063 strncpy( inBuffer
, versionString
, inBufferSize
);
5064 inBuffer
[ inBufferSize
] = '\0';
5070 //===========================================================================================================================
5072 //===========================================================================================================================
5075 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
5081 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
5092 *string
= (char*) malloc( *stringLen
);
5093 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
5095 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
5099 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
5101 require_noerr_quiet( err
, exit
);
5105 DWORD dwSize
= sizeof( DWORD
);
5107 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
5119 //===========================================================================================================================
5121 //===========================================================================================================================
5123 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
5125 struct sockaddr_in6 sa6
;
5126 struct sockaddr_in sa4
;
5130 sa6
.sin6_family
= AF_INET6
;
5131 dwSize
= sizeof( sa6
);
5133 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
5135 if ( err
== mStatus_NoError
)
5137 err
= SetupAddr( ip
, (struct sockaddr
*) &sa6
);
5138 require_noerr( err
, exit
);
5142 sa4
.sin_family
= AF_INET
;
5143 dwSize
= sizeof( sa4
);
5145 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
5146 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
5147 require_noerr( err
, exit
);
5149 err
= SetupAddr( ip
, (struct sockaddr
*) &sa4
);
5150 require_noerr( err
, exit
);
5159 //===========================================================================================================================
5161 //===========================================================================================================================
5163 mDNSlocal
struct ifaddrs
*
5164 myGetIfAddrs(int refresh
)
5166 static struct ifaddrs
*ifa
= NULL
;
5183 //===========================================================================================================================
5185 //===========================================================================================================================
5188 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
5190 #if( defined( UNICODE ) || defined( _UNICODE ) )
5194 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
5195 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5196 require_noerr( err
, exit
);
5201 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
5206 //===========================================================================================================================
5207 // WindowsLatin1toUTF8
5208 //===========================================================================================================================
5211 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
5219 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
5221 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
5222 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5223 require_noerr( err
, exit
);
5225 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
5226 require_action( utf16
, exit
, err
= kNoMemoryErr
);
5228 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
5229 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5230 require_noerr( err
, exit
);
5232 // Now convert the temporary UTF-16 to UTF-8.
5234 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
5235 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5236 require_noerr( err
, exit
);
5239 if( utf16
) free( utf16
);
5244 //===========================================================================================================================
5245 // FreeTCPConnectionData
5246 //===========================================================================================================================
5249 FreeTCPSocket( TCPSocket
*sock
)
5253 if ( sock
->pendingEvent
)
5255 CloseHandle( sock
->pendingEvent
);
5258 if ( sock
->fd
!= INVALID_SOCKET
)
5260 closesocket( sock
->fd
);
5267 //===========================================================================================================================
5269 //===========================================================================================================================
5272 FreeUDPSocket( UDPSocket
* sock
)
5276 if ( sock
->readEvent
)
5278 CloseHandle( sock
->readEvent
);
5281 if ( sock
->sock
!= INVALID_SOCKET
)
5283 closesocket( sock
->sock
);
5289 //===========================================================================================================================
5291 //===========================================================================================================================
5293 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
5295 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
5297 if (sa
->sa_family
== AF_INET
)
5299 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
5300 ip
->type
= mDNSAddrType_IPv4
;
5301 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
5302 return(mStatus_NoError
);
5305 if (sa
->sa_family
== AF_INET6
)
5307 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
5308 ip
->type
= mDNSAddrType_IPv6
;
5309 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.u
.Word
[1] = 0;
5310 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
5311 return(mStatus_NoError
);
5314 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
5315 return(mStatus_Invalid
);
5319 mDNSlocal
void GetDDNSFQDN( domainname
*const fqdn
)
5333 // Get info from Bonjour registry key
5335 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
5336 require_noerr( err
, exit
);
5338 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
5339 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
5341 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
5343 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
5364 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCWSTR lpSubKey
)
5366 mDNSlocal
void GetDDNSConfig( DNameListElem
** domains
, LPCSTR lpSubKey
)
5369 char subKeyName
[kRegistryMaxKeyLength
+ 1];
5386 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, lpSubKey
, &key
);
5387 require_noerr( err
, exit
);
5389 // Get information about this node
5391 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
5392 require_noerr( err
, exit
);
5394 for ( i
= 0; i
< cSubKeys
; i
++)
5398 dwSize
= kRegistryMaxKeyLength
;
5400 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
5404 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
5405 require_noerr( err
, exit
);
5407 dwSize
= sizeof( DWORD
);
5408 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
5410 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
5412 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
5414 dlog( kDebugLevelError
, "bad DDNS domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
5418 DNameListElem
* domain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
5419 require_action( domain
, exit
, err
= mStatus_NoMemoryErr
);
5421 AssignDomainName(&domain
->name
, &dname
);
5422 domain
->next
= *domains
;
5428 RegCloseKey( subKey
);
5437 RegCloseKey( subKey
);
5447 mDNSlocal
void SetDomainSecret( mDNS
* const m
, const domainname
* inDomain
)
5449 char domainUTF8
[ 256 ];
5450 DomainAuthInfo
*foundInList
;
5451 DomainAuthInfo
*ptr
;
5452 char outDomain
[ 256 ];
5454 char outSecret
[ 256 ];
5457 ConvertDomainNameToCString( inDomain
, domainUTF8
);
5459 // If we're able to find a secret for this domain
5461 if ( LsaGetSecret( domainUTF8
, outDomain
, sizeof( outDomain
), outKey
, sizeof( outKey
), outSecret
, sizeof( outSecret
) ) )
5466 // Tell the core about this secret
5468 MakeDomainNameFromDNSNameString( &domain
, outDomain
);
5469 MakeDomainNameFromDNSNameString( &key
, outKey
);
5471 for (foundInList
= m
->AuthInfoList
; foundInList
; foundInList
= foundInList
->next
)
5472 if (SameDomainName(&foundInList
->domain
, &domain
) ) break;
5478 ptr
= (DomainAuthInfo
*)malloc(sizeof(DomainAuthInfo
));
5479 require_action( ptr
, exit
, err
= mStatus_NoMemoryErr
);
5482 err
= mDNS_SetSecretForDomain(m
, ptr
, &domain
, &key
, outSecret
, mDNSfalse
);
5483 require_action( err
!= mStatus_BadParamErr
, exit
, if (!foundInList
) mDNSPlatformMemFree( ptr
) );
5485 debugf("Setting shared secret for zone %s with key %##s", outDomain
, key
.c
);
5495 CheckFileShares( mDNS
* const m
)
5497 PSHARE_INFO_1 bufPtr
= ( PSHARE_INFO_1
) NULL
;
5498 DWORD entriesRead
= 0;
5499 DWORD totalEntries
= 0;
5501 mDNSBool enabled
= mDNSfalse
;
5507 if ( mDNSIsFileAndPrintSharingEnabled() )
5509 dlog( kDebugLevelTrace
, DEBUG_NAME
"file and print sharing is enabled\n" );
5511 res
= NetShareEnum( NULL
, 1, ( LPBYTE
* )&bufPtr
, MAX_PREFERRED_LENGTH
, &entriesRead
, &totalEntries
, &resume
);
5513 if ( ( res
== ERROR_SUCCESS
) || ( res
== ERROR_MORE_DATA
) )
5515 PSHARE_INFO_1 p
= bufPtr
;
5518 for( i
= 0; i
<= totalEntries
; i
++ )
5520 // We are only interested if the user is sharing anything other
5521 // than the built-in "print$" source
5523 if ( ( p
->shi1_type
== STYPE_DISKTREE
) && ( wcscmp( p
->shi1_netname
, TEXT( "print$" ) ) != 0 ) )
5532 NetApiBufferFree( bufPtr
);
5537 if ( enabled
&& !m
->p
->smbRegistered
)
5541 mDNSIPPort port
= { { SMBPortAsNumber
>> 8, SMBPortAsNumber
& 0xFF } };
5542 mDNSInterfaceID iid
= mDNSPlatformInterfaceIDfromInterfaceIndex( m
, 0 );
5544 dlog( kDebugLevelTrace
, DEBUG_NAME
"registering smb type\n" );
5546 MakeDomainNameFromDNSNameString(&type
, "_smb._tcp" );
5547 MakeDomainNameFromDNSNameString(&domain
, "local.");
5549 err
= mDNS_RegisterService( m
, &m
->p
->smbSRS
, &m
->nicelabel
, &type
, &domain
, NULL
, port
, NULL
, 0, NULL
, 0, iid
, /* callback */ NULL
, /* context */ NULL
);
5550 require_noerr( err
, exit
);
5552 m
->p
->smbRegistered
= mDNStrue
;
5554 else if ( !enabled
&& m
->p
->smbRegistered
)
5556 dlog( kDebugLevelTrace
, DEBUG_NAME
"deregistering smb type\n" );
5558 err
= mDNS_DeregisterService( m
, &m
->p
->smbSRS
);
5559 require_noerr( err
, exit
);
5561 m
->p
->smbRegistered
= mDNSfalse
;
5571 UpdateWOMPConfig( mDNS
* const m
)
5573 mDNSInterfaceData
* ifd
;
5575 mDNSPlatformLock( m
);
5577 m
->p
->womp
= mDNSfalse
;
5579 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
5581 ifd
->interfaceInfo
.NetWake
= IsWOMPEnabled( ifd
->name
);
5583 if ( ifd
->interfaceInfo
.NetWake
)
5585 m
->p
->womp
= mDNStrue
;
5589 mDNSPlatformUnlock( m
);
5594 IsWOMPEnabled( const char * adapterName
)
5599 HANDLE handle
= INVALID_HANDLE_VALUE
;
5600 NDIS_PNP_CAPABILITIES
* pNPC
= NULL
;
5604 // Construct a device name to pass to CreateFile
5606 strncpy_s( fileName
, sizeof( fileName
), DEVICE_PREFIX
, strlen( DEVICE_PREFIX
) );
5607 strcat_s( fileName
, sizeof( fileName
), adapterName
);
5608 handle
= CreateFileA( fileName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, INVALID_HANDLE_VALUE
);
5609 require_action ( handle
!= INVALID_HANDLE_VALUE
, exit
, ok
= FALSE
);
5611 // We successfully opened the driver, format the IOCTL to pass the driver.
5613 oid
= OID_PNP_CAPABILITIES
;
5614 pNPC
= ( NDIS_PNP_CAPABILITIES
* ) malloc( sizeof( NDIS_PNP_CAPABILITIES
) );
5615 require_action( pNPC
!= NULL
, exit
, ok
= FALSE
);
5616 ok
= ( mDNSu8
) DeviceIoControl( handle
, IOCTL_NDIS_QUERY_GLOBAL_STATS
, &oid
, sizeof( oid
), pNPC
, sizeof( NDIS_PNP_CAPABILITIES
), &count
, NULL
);
5617 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
5618 require_action( !err
, exit
, ok
= FALSE
);
5619 ok
= ( mDNSu8
) ( ( count
== sizeof( NDIS_PNP_CAPABILITIES
) ) && ( pNPC
->Flags
& NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE
) );
5628 if ( handle
!= INVALID_HANDLE_VALUE
)
5630 CloseHandle( handle
);
5633 return ( mDNSu8
) ok
;