2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.83 2005/03/07 18:27:42 shersche
27 <rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
29 Revision 1.82 2005/03/06 05:20:24 shersche
30 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
32 Revision 1.81 2005/03/04 22:44:53 shersche
33 <rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
35 Revision 1.80 2005/03/03 21:07:38 shersche
36 <rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
38 Revision 1.79 2005/03/03 02:29:00 shersche
39 Use the RegNames.h header file for registry key names
41 Revision 1.78 2005/03/02 04:04:17 shersche
42 Support for multiple browse domains
44 Revision 1.77 2005/02/25 20:02:18 shersche
45 <rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
47 Revision 1.76 2005/02/23 02:59:20 shersche
48 <rdar://problem/4013482> Check to see if locks have been initialized before using them.
50 Revision 1.75 2005/02/16 02:36:25 shersche
51 <rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
53 Revision 1.74 2005/02/08 06:06:16 shersche
54 <rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
56 Revision 1.73 2005/02/01 19:35:43 ksekar
57 Removed obsolete arguments from mDNS_SetSecretForZone
59 Revision 1.72 2005/02/01 01:38:53 shersche
60 Handle null DynDNS configuration more gracefully
62 Revision 1.71 2005/01/27 22:57:57 cheshire
63 Fix compile errors on gcc4
65 Revision 1.70 2005/01/25 08:12:52 shersche
66 <rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
69 Revision 1.69 2005/01/11 04:39:48 shersche
70 Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
72 Revision 1.68 2005/01/11 02:04:48 shersche
73 Gracefully handle when IPv6 is not installed on a user's machine
75 Revision 1.67 2004/12/18 00:51:52 cheshire
76 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
78 Revision 1.66 2004/12/17 23:37:49 cheshire
79 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
80 (and other repetitive configuration changes)
82 Revision 1.65 2004/12/15 07:34:45 shersche
83 Add platform support for IPv4 and IPv6 unicast sockets
85 Revision 1.64 2004/12/15 06:06:15 shersche
86 Fix problem in obtaining IPv6 subnet mask
88 Revision 1.63 2004/11/23 03:39:47 cheshire
89 Let interface name/index mapping capability live directly in JNISupport.c,
90 instead of having to call through to the daemon via IPC to get this information.
92 Revision 1.62 2004/11/12 03:16:41 rpantos
93 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
95 Revision 1.61 2004/11/05 22:54:38 shersche
96 Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
97 Submitted by: Pavel Repin <prepin@gmail.com>
99 Revision 1.60 2004/11/05 22:41:56 shersche
100 Determine subnet mask when populating network interface data structures
101 Submitted by: Pavel Repin <prepin@gmail.com>
104 Revision 1.59 2004/10/28 03:24:42 cheshire
105 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
107 Revision 1.58 2004/10/16 00:17:01 cheshire
108 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
110 Revision 1.57 2004/10/11 21:53:15 shersche
111 <rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
114 Revision 1.56 2004/09/26 23:20:36 ksekar
115 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
117 Revision 1.55 2004/09/21 21:02:57 cheshire
118 Set up ifname before calling mDNS_RegisterInterface()
120 Revision 1.54 2004/09/17 01:08:57 cheshire
121 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
122 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
123 declared in that file are ONLY appropriate to single-address-space embedded applications.
124 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
126 Revision 1.53 2004/09/17 00:19:11 cheshire
127 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
129 Revision 1.52 2004/09/16 00:24:50 cheshire
130 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
132 Revision 1.51 2004/09/14 23:42:37 cheshire
133 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
135 Revision 1.50 2004/08/25 23:36:56 shersche
136 <rdar://problem/3658379> Remove code that retrieves TTL from received packets
139 Revision 1.49 2004/08/25 16:43:29 ksekar
140 Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
143 Revision 1.48 2004/08/14 03:22:43 cheshire
144 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
145 Add GetUserSpecifiedDDNSName() routine
146 Convert ServiceRegDomain to domainname instead of C string
147 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
149 Revision 1.47 2004/08/06 17:33:02 shersche
150 <rdar://problem/3753797> Put correct length of string in first byte of nicelabel
153 Revision 1.46 2004/08/05 05:43:01 shersche
154 <rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
157 Revision 1.45 2004/07/26 22:49:31 ksekar
158 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
160 Revision 1.44 2004/07/26 05:42:50 shersche
161 use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
163 Revision 1.43 2004/07/13 21:24:25 rpantos
164 Fix for <rdar://problem/3701120>.
166 Revision 1.42 2004/06/24 15:23:24 shersche
167 Add InterfaceListChanged callback. This callback is used in Service.c to add link local routes to the routing table
168 Submitted by: herscher
170 Revision 1.41 2004/06/18 05:22:16 rpantos
171 Integrate Scott's changes
173 Revision 1.40 2004/05/26 09:06:07 bradley
174 Retry while building the interface list if it returns an error since the two-step process required to
175 get the interface list could allow a subsequent interface change to come in that window and change the
176 needed size after getting the size, but before getting the list, causing it to return an error.
177 Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
179 Revision 1.39 2004/05/18 23:51:27 cheshire
180 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
182 Revision 1.38 2004/05/13 04:57:48 ksekar
183 Removed unnecessary FreeSearchList function
185 Revision 1.37 2004/05/13 04:54:20 ksekar
186 Unified list copy/free code. Added symetric list for
188 Revision 1.36 2004/05/12 22:03:09 ksekar
189 Made GetSearchDomainList a true platform-layer call (declaration moved
190 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
191 only on non-OSX platforms. Changed call to return a copy of the list
192 to avoid shared memory issues. Added a routine to free the list.
194 Revision 1.35 2004/04/21 02:49:12 cheshire
195 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
197 Revision 1.34 2004/04/15 01:00:05 bradley
198 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
199 without .local name resolving support will need to manually query for A/AAAA records as needed.
201 Revision 1.33 2004/04/14 23:09:29 ksekar
202 Support for TSIG signed dynamic updates.
204 Revision 1.32 2004/04/09 17:40:26 cheshire
205 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
207 Revision 1.31 2004/04/09 00:40:46 bradley
208 Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
210 Revision 1.30 2004/04/09 00:33:58 bradley
211 Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
213 Revision 1.29 2004/03/15 02:07:46 bradley
214 Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
215 handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
216 does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
218 Revision 1.28 2004/03/07 00:26:39 bradley
219 Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
220 Added count assert when building the wait list to catch underruns/overruns if the code is changed.
222 Revision 1.27 2004/01/30 02:44:32 bradley
223 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
224 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
225 are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
226 (it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
227 software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
228 reporting HINFO records with the Windows and mDNSResponder version information.
230 Revision 1.26 2004/01/24 04:59:16 cheshire
231 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
233 Revision 1.25 2003/11/14 20:59:09 cheshire
234 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
235 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
237 Revision 1.24 2003/10/24 23:23:02 bradley
238 Removed legacy port 53 support as it is no longer needed.
240 Revision 1.23 2003/10/14 03:26:12 bradley
241 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
243 Revision 1.22 2003/08/20 06:21:25 bradley
244 Updated to latest internal version of the mDNSWindows platform layer: Added support
245 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
246 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
247 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
248 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
249 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
250 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
251 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
252 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
254 Revision 1.21 2003/08/18 23:09:57 cheshire
255 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
257 Revision 1.20 2003/08/12 19:56:27 cheshire
260 Revision 1.19 2003/08/05 23:58:18 cheshire
261 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
262 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
264 Revision 1.18 2003/07/23 21:16:30 cheshire
265 Removed a couple of debugfs
267 Revision 1.17 2003/07/23 02:23:01 cheshire
268 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
269 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
271 Revision 1.16 2003/07/19 03:15:16 cheshire
272 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
273 and add the obvious trivial implementations to each platform support layer
275 Revision 1.15 2003/07/02 21:20:04 cheshire
276 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
278 Revision 1.14 2003/05/26 03:21:30 cheshire
279 Tidy up address structure naming:
280 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
281 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
282 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
284 Revision 1.13 2003/05/26 03:01:28 cheshire
285 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
287 Revision 1.12 2003/05/06 21:06:05 cheshire
288 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
290 Revision 1.11 2003/05/06 00:00:51 cheshire
291 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
293 Revision 1.10 2003/04/29 00:06:09 cheshire
294 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
296 Revision 1.9 2003/04/26 02:40:01 cheshire
297 Add void LogMsg( const char *format, ... )
299 Revision 1.8 2003/03/22 02:57:44 cheshire
300 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
302 Revision 1.7 2003/03/15 04:40:38 cheshire
303 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
305 Revision 1.6 2003/02/21 01:54:10 cheshire
306 <rdar://problem/3099194> mDNSResponder needs performance improvements
307 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
309 Revision 1.5 2003/02/20 00:59:03 cheshire
310 Brought Windows code up to date so it complies with
311 Josh Graessley's interface changes for IPv6 support.
312 (Actual support for IPv6 on Windows will come later.)
314 Revision 1.4 2002/09/21 20:44:54 zarzycki
317 Revision 1.3 2002/09/20 05:50:45 bradley
318 Multicast DNS platform plugin for Win32
322 - Get unicode name of machine for nice name instead of just the host name.
323 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
324 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
325 - Implement TCP support for truncated packets (only stubs now).
334 #include "CommonServices.h"
335 #include "DebugServices.h"
336 #include "RegNames.h"
339 #include <Iphlpapi.h>
340 #if( !TARGET_OS_WINDOWS_CE )
343 #include <ntsecapi.h>
346 #include "mDNSEmbeddedAPI.h"
348 #include "mDNSWin32.h"
351 #pragma mark == Constants ==
354 //===========================================================================================================================
356 //===========================================================================================================================
358 #define DEBUG_NAME "[mDNSWin32] "
360 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
361 #define MDNS_WINDOWS_ENABLE_IPV4 1
362 #define MDNS_WINDOWS_ENABLE_IPV6 1
363 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
365 #define kMDNSDefaultName "My Computer"
367 #define kWinSockMajorMin 2
368 #define kWinSockMinorMin 2
370 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
371 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
372 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
373 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
374 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
375 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
376 #define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
378 #define kRegistryMaxKeyLength 255
380 #if( !TARGET_OS_WINDOWS_CE )
381 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
386 #pragma mark == Prototypes ==
389 //===========================================================================================================================
391 //===========================================================================================================================
393 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
394 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
395 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
396 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
397 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
398 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
399 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
400 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
401 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
402 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
403 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
404 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
405 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
407 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
408 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
409 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
410 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
411 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
412 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
);
413 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
414 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
* inMDNS
);
415 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
);
416 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
* inMDNS
);
419 // Platform Accessors
425 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
426 struct mDNSPlatformInterfaceInfo
432 typedef struct mDNSTCPConnectionData mDNSTCPConnectionData
;
433 struct mDNSTCPConnectionData
437 TCPConnectionCallback callback
;
440 mDNSTCPConnectionData
* next
;
444 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
445 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
449 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
450 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
453 #if( !TARGET_OS_WINDOWS_CE )
454 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
457 #if( TARGET_OS_WINDOWS_CE )
458 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
461 mDNSlocal mDNSBool
CanReceiveUnicast( void );
463 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
464 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
465 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
466 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
467 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
468 mDNSlocal OSStatus
ConvertUTF8ToLsaString( const char * input
, PLSA_UNICODE_STRING output
);
469 mDNSlocal OSStatus
ConvertLsaStringToUTF8( PLSA_UNICODE_STRING input
, char ** output
);
470 mDNSlocal
void FreeTCPConnectionData( mDNSTCPConnectionData
* data
);
477 #pragma mark == Globals ==
480 //===========================================================================================================================
482 //===========================================================================================================================
484 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
485 mDNSs32 mDNSPlatformOneSecond
= 0;
486 mDNSlocal mDNSTCPConnectionData
* gTCPConnectionList
= NULL
;
487 mDNSlocal
int gTCPConnections
= 0;
488 mDNSlocal BOOL gWaitListChanged
= FALSE
;
490 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
493 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
497 PIP_ADAPTER_ADDRESSES inAdapter
,
498 PULONG outBufferSize
);
500 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
501 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
507 #pragma mark == Platform Support ==
510 //===========================================================================================================================
512 //===========================================================================================================================
514 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
519 struct sockaddr_in sa4
;
520 struct sockaddr_in6 sa6
;
524 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
526 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
527 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
529 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
530 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
531 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
532 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
534 // Startup WinSock 2.2 or later.
536 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
537 require_noerr( err
, exit
);
539 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
540 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
542 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
544 // Setup the HINFO HW/SW strings.
546 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
548 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
549 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
551 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
552 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
553 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
554 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
556 // Set up the IPv4 unicast socket
558 inMDNS
->p
->unicastSock4
= INVALID_SOCKET
;
559 inMDNS
->p
->unicastSock4ReadEvent
= NULL
;
560 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
562 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
564 sa4
.sin_family
= AF_INET
;
565 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
566 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
);
568 sa4len
= sizeof( sa4
);
569 err
= getsockname( inMDNS
->p
->unicastSock4
, (struct sockaddr
*) &sa4
, &sa4len
);
570 require_noerr( err
, exit
);
571 inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
572 inMDNS
->p
->unicastSock4ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
573 err
= translate_errno( inMDNS
->p
->unicastSock4ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
574 require_noerr( err
, exit
);
575 err
= WSAEventSelect( inMDNS
->p
->unicastSock4
, inMDNS
->p
->unicastSock4ReadEvent
, FD_READ
);
576 require_noerr( err
, exit
);
577 #if( !TARGET_OS_WINDOWS_CE )
581 err
= WSAIoctl( inMDNS
->p
->unicastSock4
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
582 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock4RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock4RecvMsgPtr
), &size
, NULL
, NULL
);
586 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
593 // Set up the IPv6 unicast socket
595 inMDNS
->p
->unicastSock6
= INVALID_SOCKET
;
596 inMDNS
->p
->unicastSock6ReadEvent
= NULL
;
597 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
599 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
601 sa6
.sin6_family
= AF_INET6
;
602 sa6
.sin6_addr
= in6addr_any
;
603 sa6
.sin6_scope_id
= 0;
605 // This call will fail if the machine hasn't installed IPv6. In that case,
606 // the error will be WSAEAFNOSUPPORT.
608 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
);
609 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
610 inMDNS
->p
->unicastSock6ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
611 err
= translate_errno( inMDNS
->p
->unicastSock6ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
612 require_noerr( err
, exit
);
614 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
616 if ( inMDNS
->p
->unicastSock6
!= INVALID_SOCKET
)
618 sa6len
= sizeof( sa6
);
619 err
= getsockname( inMDNS
->p
->unicastSock6
, (struct sockaddr
*) &sa6
, &sa6len
);
620 require_noerr( err
, exit
);
621 inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
623 err
= WSAEventSelect( inMDNS
->p
->unicastSock6
, inMDNS
->p
->unicastSock6ReadEvent
, FD_READ
);
624 require_noerr( err
, exit
);
626 #if( !TARGET_OS_WINDOWS_CE )
630 err
= WSAIoctl( inMDNS
->p
->unicastSock6
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
631 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock6RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock6RecvMsgPtr
), &size
, NULL
, NULL
);
635 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
643 // Set up the mDNS thread.
645 err
= SetupSynchronizationObjects( inMDNS
);
646 require_noerr( err
, exit
);
648 err
= SetupThread( inMDNS
);
649 require_noerr( err
, exit
);
653 mDNSCoreInitComplete( inMDNS
, err
);
658 mDNSPlatformClose( inMDNS
);
660 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
664 //===========================================================================================================================
666 //===========================================================================================================================
668 void mDNSPlatformClose( mDNS
* const inMDNS
)
672 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
675 // Tear everything down in reverse order to how it was set up.
677 err
= TearDownThread( inMDNS
);
680 err
= TearDownInterfaceList( inMDNS
);
682 check( !inMDNS
->p
->inactiveInterfaceList
);
684 err
= TearDownSynchronizationObjects( inMDNS
);
687 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
689 if ( inMDNS
->p
->unicastSock4ReadEvent
)
691 CloseHandle( inMDNS
->p
->unicastSock4ReadEvent
);
692 inMDNS
->p
->unicastSock4ReadEvent
= 0;
695 if ( IsValidSocket( inMDNS
->p
->unicastSock4
) )
697 close_compat( inMDNS
->p
->unicastSock4
);
702 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
704 if ( inMDNS
->p
->unicastSock6ReadEvent
)
706 CloseHandle( inMDNS
->p
->unicastSock6ReadEvent
);
707 inMDNS
->p
->unicastSock6ReadEvent
= 0;
710 if ( IsValidSocket( inMDNS
->p
->unicastSock6
) )
712 close_compat( inMDNS
->p
->unicastSock6
);
717 // Free the DLL needed for IPv6 support.
719 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
720 if( gIPHelperLibraryInstance
)
722 gGetAdaptersAddressesFunctionPtr
= NULL
;
724 FreeLibrary( gIPHelperLibraryInstance
);
725 gIPHelperLibraryInstance
= NULL
;
731 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
734 //===========================================================================================================================
735 // mDNSPlatformSendUDP
736 //===========================================================================================================================
740 const mDNS
* const inMDNS
,
741 const void * const inMsg
,
742 const mDNSu8
* const inMsgEnd
,
743 mDNSInterfaceID inInterfaceID
,
744 const mDNSAddr
* inDstIP
,
745 mDNSIPPort inDstPort
)
747 SOCKET sendingsocket
= INVALID_SOCKET
;
748 mStatus err
= mStatus_NoError
;
749 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
750 struct sockaddr_storage addr
;
753 DEBUG_USE_ONLY( inMDNS
);
755 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
761 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
763 if( inDstIP
->type
== mDNSAddrType_IPv4
)
765 struct sockaddr_in
* sa4
;
767 sa4
= (struct sockaddr_in
*) &addr
;
768 sa4
->sin_family
= AF_INET
;
769 sa4
->sin_port
= inDstPort
.NotAnInteger
;
770 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
771 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock4
;
773 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
775 struct sockaddr_in6
* sa6
;
777 sa6
= (struct sockaddr_in6
*) &addr
;
778 sa6
->sin6_family
= AF_INET6
;
779 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
780 sa6
->sin6_flowinfo
= 0;
781 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
782 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
783 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock6
;
787 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
788 err
= mStatus_BadParamErr
;
792 if (IsValidSocket(sendingsocket
))
794 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
795 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
796 require_noerr( err
, exit
);
803 //===========================================================================================================================
805 //===========================================================================================================================
807 void mDNSPlatformLock( const mDNS
* const inMDNS
)
811 if ( inMDNS
->p
->lockInitialized
)
813 EnterCriticalSection( &inMDNS
->p
->lock
);
817 //===========================================================================================================================
818 // mDNSPlatformUnlock
819 //===========================================================================================================================
821 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
826 if ( inMDNS
->p
->lockInitialized
)
828 check( inMDNS
->p
->threadID
);
830 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
831 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
833 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
837 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
838 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
840 LeaveCriticalSection( &inMDNS
->p
->lock
);
844 //===========================================================================================================================
845 // mDNSPlatformStrCopy
846 //===========================================================================================================================
848 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
853 strcpy( (char *) inDst
, (const char*) inSrc
);
856 //===========================================================================================================================
857 // mDNSPlatformStrLen
858 //===========================================================================================================================
860 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
864 return( (mDNSu32
) strlen( (const char *) inSrc
) );
867 //===========================================================================================================================
868 // mDNSPlatformMemCopy
869 //===========================================================================================================================
871 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
876 memcpy( inDst
, inSrc
, inSize
);
879 //===========================================================================================================================
880 // mDNSPlatformMemSame
881 //===========================================================================================================================
883 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
888 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
891 //===========================================================================================================================
892 // mDNSPlatformMemZero
893 //===========================================================================================================================
895 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
899 memset( inDst
, 0, inSize
);
902 //===========================================================================================================================
903 // mDNSPlatformMemAllocate
904 //===========================================================================================================================
906 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
912 mem
= malloc( inSize
);
918 //===========================================================================================================================
919 // mDNSPlatformMemFree
920 //===========================================================================================================================
922 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
929 //===========================================================================================================================
930 // mDNSPlatformRandomSeed
931 //===========================================================================================================================
933 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
935 return( GetTickCount() );
938 //===========================================================================================================================
939 // mDNSPlatformTimeInit
940 //===========================================================================================================================
942 mDNSexport mStatus
mDNSPlatformTimeInit( void )
944 // No special setup is required on Windows -- we just use GetTickCount().
945 return( mStatus_NoError
);
948 //===========================================================================================================================
949 // mDNSPlatformRawTime
950 //===========================================================================================================================
952 mDNSs32
mDNSPlatformRawTime( void )
954 return( (mDNSs32
) GetTickCount() );
957 //===========================================================================================================================
959 //===========================================================================================================================
961 mDNSexport mDNSs32
mDNSPlatformUTC( void )
966 //===========================================================================================================================
967 // mDNSPlatformInterfaceNameToID
968 //===========================================================================================================================
970 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
973 mDNSInterfaceData
* ifd
;
979 // Search for an interface with the specified name,
981 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
983 if( strcmp( ifd
->name
, inName
) == 0 )
988 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
994 *outID
= (mDNSInterfaceID
) ifd
;
996 err
= mStatus_NoError
;
1002 //===========================================================================================================================
1003 // mDNSPlatformInterfaceIDToInfo
1004 //===========================================================================================================================
1006 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
1009 mDNSInterfaceData
* ifd
;
1015 // Search for an interface with the specified ID,
1017 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1019 if( ifd
== (mDNSInterfaceData
*) inID
)
1024 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1028 outInfo
->name
= ifd
->name
;
1029 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
1030 err
= mStatus_NoError
;
1036 //===========================================================================================================================
1037 // mDNSPlatformInterfaceIDfromInterfaceIndex
1038 //===========================================================================================================================
1040 mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS
* const inMDNS
, mDNSu32 inIndex
)
1045 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
1047 id
= mDNSInterface_LocalOnly
;
1049 else if( inIndex
!= 0 )
1051 mDNSInterfaceData
* ifd
;
1053 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1055 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
1057 id
= ifd
->interfaceInfo
.InterfaceID
;
1066 //===========================================================================================================================
1067 // mDNSPlatformInterfaceIndexfromInterfaceID
1068 //===========================================================================================================================
1070 mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS
* const inMDNS
, mDNSInterfaceID inID
)
1075 if( inID
== mDNSInterface_LocalOnly
)
1077 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
1081 mDNSInterfaceData
* ifd
;
1083 // Search active interfaces.
1084 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1086 if( (mDNSInterfaceID
) ifd
== inID
)
1088 index
= ifd
->scopeID
;
1093 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
1097 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
1099 if( (mDNSInterfaceID
) ifd
== inID
)
1101 index
= ifd
->scopeID
;
1111 //===========================================================================================================================
1112 // mDNSPlatformTCPConnect
1113 //===========================================================================================================================
1116 mDNSPlatformTCPConnect(
1117 const mDNSAddr
* inDstIP
,
1118 mDNSOpaque16 inDstPort
,
1119 mDNSInterfaceID inInterfaceID
,
1120 TCPConnectionCallback inCallback
,
1124 u_long on
= 1; // "on" for setsockopt
1125 struct sockaddr_in saddr
;
1126 mDNSTCPConnectionData
* tcd
= NULL
;
1127 mStatus err
= mStatus_NoError
;
1129 DEBUG_UNUSED( inInterfaceID
);
1131 *outSock
= INVALID_SOCKET
;
1133 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1135 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1136 return mStatus_UnknownErr
;
1139 // Setup connection data object
1141 tcd
= (mDNSTCPConnectionData
*) malloc( sizeof( mDNSTCPConnectionData
) );
1142 require_action( tcd
, exit
, err
= mStatus_NoMemoryErr
);
1143 memset( tcd
, 0, sizeof( mDNSTCPConnectionData
) );
1145 tcd
->sock
= INVALID_SOCKET
;
1146 tcd
->callback
= inCallback
;
1147 tcd
->context
= inContext
;
1149 bzero(&saddr
, sizeof(saddr
));
1150 saddr
.sin_family
= AF_INET
;
1151 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1152 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1154 // Create the socket
1156 tcd
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
1157 err
= translate_errno( tcd
->sock
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
1158 require_noerr( err
, exit
);
1160 // Set it to be non-blocking
1162 err
= ioctlsocket( tcd
->sock
, FIONBIO
, &on
);
1163 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1164 require_noerr( err
, exit
);
1166 // Try and do connect
1168 err
= connect( tcd
->sock
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1169 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1170 tcd
->connected
= !err
? TRUE
: FALSE
;
1171 tcd
->pendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1172 err
= translate_errno( tcd
->pendingEvent
, GetLastError(), mStatus_UnknownErr
);
1173 require_noerr( err
, exit
);
1174 err
= WSAEventSelect( tcd
->sock
, tcd
->pendingEvent
, FD_CONNECT
|FD_READ
|FD_CLOSE
);
1175 require_noerr( err
, exit
);
1179 tcd
->next
= gTCPConnectionList
;
1180 gTCPConnectionList
= tcd
;
1182 gWaitListChanged
= TRUE
;
1184 *outSock
= (int) tcd
->sock
;
1190 err
= tcd
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1194 FreeTCPConnectionData( tcd
);
1200 //===========================================================================================================================
1201 // mDNSPlatformTCPCloseConnection
1202 //===========================================================================================================================
1204 void mDNSPlatformTCPCloseConnection( int inSock
)
1206 mDNSTCPConnectionData
* tcd
= gTCPConnectionList
;
1207 mDNSTCPConnectionData
* last
= NULL
;
1211 if ( tcd
->sock
== ( SOCKET
) inSock
)
1215 gTCPConnectionList
= tcd
->next
;
1219 last
->next
= tcd
->next
;
1222 FreeTCPConnectionData( tcd
);
1225 gWaitListChanged
= TRUE
;
1235 //===========================================================================================================================
1236 // mDNSPlatformReadTCP
1237 //===========================================================================================================================
1239 int mDNSPlatformReadTCP( int inSock
, void *inBuffer
, int inBufferSize
)
1244 nread
= recv( inSock
, inBuffer
, inBufferSize
, 0);
1245 err
= translate_errno( ( nread
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1246 require_noerr( err
, exit
);
1258 //===========================================================================================================================
1259 // mDNSPlatformWriteTCP
1260 //===========================================================================================================================
1262 int mDNSPlatformWriteTCP( int inSock
, const char *inMsg
, int inMsgSize
)
1267 nsent
= send( inSock
, inMsg
, inMsgSize
, 0 );
1269 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1270 require_noerr( err
, exit
);
1282 //===========================================================================================================================
1283 // dDNSPlatformGetConfig
1284 //===========================================================================================================================
1287 dDNSPlatformGetConfig(domainname
* const fqdn
, domainname
*const regDomain
, DNameListElem
** browseDomains
)
1290 char subKeyName
[kRegistryMaxKeyLength
+ 1];
1304 fqdn
->c
[0] = regDomain
->c
[0] = '\0';
1306 *browseDomains
= NULL
;
1308 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
1309 require_noerr( err
, exit
);
1311 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1312 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1314 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
1316 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
1332 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
, &key
);
1333 require_noerr( err
, exit
);
1335 // Get information about this node
1337 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
1338 require_noerr( err
, exit
);
1340 for ( i
= 0; i
< cSubKeys
; i
++)
1344 dwSize
= kRegistryMaxKeyLength
;
1346 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1350 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
1351 require_noerr( err
, exit
);
1353 dwSize
= sizeof( DWORD
);
1354 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
1356 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
1358 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
1360 dlog( kDebugLevelError
, "bad DDNS browse domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
1364 DNameListElem
* browseDomain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1365 require_action( browseDomain
, exit
, err
= mStatus_NoMemoryErr
);
1367 AssignDomainName(&browseDomain
->name
, &dname
);
1368 browseDomain
->next
= *browseDomains
;
1370 *browseDomains
= browseDomain
;
1374 RegCloseKey( subKey
);
1385 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
, &key
);
1386 require_noerr( err
, exit
);
1388 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1389 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1391 if ( !MakeDomainNameFromDNSNameString( regDomain
, name
) || !regDomain
->c
[0] )
1393 dlog( kDebugLevelError
, "bad DDNS registration domain in registry: %s", name
[0] ? name
: "(unknown)");
1401 RegCloseKey( subKey
);
1416 //===========================================================================================================================
1417 // dDNSPlatformSetNameStatus
1418 //===========================================================================================================================
1421 dDNSPlatformSetNameStatus(domainname
*const dname
, mStatus status
)
1423 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1429 ConvertDomainNameToCString(dname
, uname
);
1435 *p
= (char) tolower(*p
);
1436 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1440 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1441 name
= TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\State\\HostNames");
1442 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1443 require_noerr( err
, exit
);
1445 status
= ( status
) ? 0 : 1;
1446 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &status
, sizeof(DWORD
) );
1447 require_noerr( err
, exit
);
1460 //===========================================================================================================================
1461 // dDNSPlatformSetSecretForDomain
1462 //===========================================================================================================================
1465 dDNSPlatformSetSecretForDomain( mDNS
*m
, const domainname
* domain
)
1467 char dstring
[MAX_ESCAPED_DOMAIN_NAME
];
1472 LSA_OBJECT_ATTRIBUTES attrs
;
1473 LSA_HANDLE handle
= NULL
;
1474 LSA_UNICODE_STRING keyName
= { 0, 0, NULL
};
1475 LSA_UNICODE_STRING
* secret
= NULL
;
1476 char * converted
= NULL
;
1480 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
1482 ConvertDomainNameToCString(domain
, dstring
);
1483 dlen
= strlen(dstring
);
1484 for (i
= 0; i
< dlen
; i
++)
1486 dstring
[i
] = (char) tolower(dstring
[i
]); // canonicalize -> lower case
1489 MakeDomainNameFromDNSNameString(&canon
, dstring
);
1492 // attrs are reserved, so initialize to zeroes.
1494 ZeroMemory(&attrs
, sizeof( attrs
) );
1496 // Get a handle to the Policy object on the local system
1498 res
= LsaOpenPolicy( NULL
, &attrs
, POLICY_GET_PRIVATE_INFORMATION
, &handle
);
1499 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1500 require_noerr( err
, exit
);
1502 // Get the encrypted data
1504 err
= ConvertUTF8ToLsaString( dstring
, &keyName
);
1505 require_noerr( err
, exit
);
1507 res
= LsaRetrievePrivateData( handle
, &keyName
, &secret
);
1508 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1509 require_noerr_quiet( err
, exit
);
1511 // Convert the unicode to string to 8 bit
1513 err
= ConvertLsaStringToUTF8( secret
, &converted
);
1514 require_noerr( err
, exit
);
1516 mDNS_SetSecretForZone( m
, d
, d
, converted
);
1528 LsaFreeMemory( secret
);
1532 if ( keyName
.Buffer
)
1534 free( keyName
.Buffer
);
1535 keyName
.Buffer
= NULL
;
1546 //===========================================================================================================================
1547 // dDNSPlatformGetSearchDomainList
1548 //===========================================================================================================================
1551 dDNSPlatformGetSearchDomainList( void )
1553 char * searchList
= NULL
;
1554 DWORD searchListLen
;
1555 DNameListElem
* head
= NULL
;
1556 DNameListElem
* current
= NULL
;
1561 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1562 require_noerr( err
, exit
);
1564 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1565 require_noerr( err
, exit
);
1567 // Windows separates the search domains with ','
1569 tok
= strtok( searchList
, "," );
1574 if ( MakeDomainNameFromDNSNameString( &domain
, tok
) )
1576 DNameListElem
* last
= current
;
1578 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1579 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1581 AssignDomainName( ¤t
->name
, &domain
);
1582 current
->next
= NULL
;
1591 last
->next
= current
;
1595 tok
= strtok( NULL
, "," );
1614 //===========================================================================================================================
1615 // dDNSPlatformGetReverseMapSearchDomainList
1616 //===========================================================================================================================
1619 dDNSPlatformGetReverseMapSearchDomainList( void )
1621 DNameListElem
* head
= NULL
;
1622 DNameListElem
* current
= NULL
;
1623 struct ifaddrs
* ifa
;
1626 ifa
= myGetIfAddrs( 1 );
1631 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !dDNS_SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1637 if (!dDNS_SetupAddr(&netmask
, ifa
->ifa_netmask
))
1639 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1640 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1641 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1642 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1644 if ( MakeDomainNameFromDNSNameString( &domain
, buffer
) )
1646 DNameListElem
* last
= current
;
1648 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1649 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1651 AssignDomainName( ¤t
->name
, &domain
);
1652 current
->next
= NULL
;
1661 last
->next
= current
;
1667 ifa
= ifa
->ifa_next
;
1676 //===========================================================================================================================
1677 // dDNSPlatformGetDNSServers
1678 //===========================================================================================================================
1681 dDNSPlatformGetDNSServers( void )
1683 FIXED_INFO
* fixedInfo
= NULL
;
1684 ULONG bufLen
= sizeof( FIXED_INFO
);
1685 IP_ADDR_STRING
* ipAddr
;
1686 IPAddrListElem
* head
= NULL
;
1687 IPAddrListElem
* current
= NULL
;
1695 GlobalFree( fixedInfo
);
1699 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1701 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1703 if ( ( err
!= ERROR_BUFFER_OVERFLOW
) || ( i
++ == 100 ) )
1709 require_noerr( err
, exit
);
1711 for ( ipAddr
= &fixedInfo
->DnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1714 IPAddrListElem
* last
= current
;
1716 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1723 current
= (IPAddrListElem
*) malloc( sizeof( IPAddrListElem
) );
1724 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1726 memcpy( ¤t
->addr
, &addr
, sizeof( mDNSAddr
) );
1727 current
->next
= NULL
;
1736 last
->next
= current
;
1744 GlobalFree( fixedInfo
);
1751 //===========================================================================================================================
1752 // dDNSPlatformGetDomainName
1753 //===========================================================================================================================
1756 dDNSPlatformGetDomainName( void )
1758 FIXED_INFO
* fixedInfo
= NULL
;
1759 ULONG bufLen
= sizeof( FIXED_INFO
);
1760 DNameListElem
* head
= NULL
;
1768 GlobalFree( fixedInfo
);
1772 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1774 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1776 if ( ( err
!= ERROR_BUFFER_OVERFLOW
) || ( i
++ == 100 ) )
1782 require_noerr( err
, exit
);
1784 if ( fixedInfo
->DomainName
)
1788 if ( MakeDomainNameFromDNSNameString( &dname
, fixedInfo
->DomainName
) || !dname
.c
[0] )
1790 head
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1791 require_action( head
, exit
, err
= mStatus_NoMemoryErr
);
1793 AssignDomainName( &head
->name
, &dname
);
1798 dlog( kDebugLevelError
, "bad DDNS host name from domain name: %s", fixedInfo
->DomainName
);
1806 GlobalFree( fixedInfo
);
1813 //===========================================================================================================================
1814 // dDNSPlatformRegisterSplitDNS
1815 //===========================================================================================================================
1818 dDNSPlatformRegisterSplitDNS( mDNS
* m
)
1822 return mStatus_UnsupportedErr
;
1826 //===========================================================================================================================
1827 // dDNSPlatformGetPrimaryInterface
1828 //===========================================================================================================================
1831 dDNSPlatformGetPrimaryInterface( mDNS
* m
, mDNSAddr
* primary
, mDNSAddr
* router
)
1833 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1834 IP_ADAPTER_INFO
* pAdapter
;
1835 DWORD bufLen
= sizeof( IP_ADAPTER_INFO
);
1838 mStatus err
= mStatus_NoError
;
1842 pAdapterInfo
= NULL
;
1845 for ( i
= 0; i
< 100; i
++ )
1849 free( pAdapterInfo
);
1850 pAdapterInfo
= NULL
;
1853 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
1854 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1856 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1858 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1864 // Windows doesn't really have a concept of a primary adapter,
1865 // so we're just going to iterate through all the adapters and
1866 // pick the first one that has an IP address assigned and
1867 // a gateway assigned
1869 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1871 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1872 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1873 pAdapter
->GatewayList
.IpAddress
.String
&&
1874 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1875 ( StringToAddress( primary
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
1876 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) )
1878 // Found one that will work
1887 // If we couldn't find one, then let's try the first one in the list
1889 err
= StringToAddress( primary
, pAdapter
->IpAddressList
.IpAddress
.String
);
1890 require_noerr( err
, exit
);
1899 free( pAdapterInfo
);
1906 //===========================================================================================================================
1907 // dDNSPlatformDefaultBrowseDomainChanged
1908 //===========================================================================================================================
1911 dDNSPlatformDefaultBrowseDomainChanged( const domainname
*d
, mDNSBool add
)
1914 DEBUG_UNUSED( add
);
1916 // This is a no-op on Windows
1920 //===========================================================================================================================
1921 // dDNSPlatformDefaultRegDomainChanged
1922 //===========================================================================================================================
1925 dDNSPlatformDefaultRegDomainChanged( const domainname
* d
, mDNSBool add
)
1928 DEBUG_UNUSED( add
);
1930 // This is a no-op on Windows
1938 //===========================================================================================================================
1940 //===========================================================================================================================
1942 #if( MDNS_DEBUGMSGS )
1943 void debugf_( const char *inFormat
, ... )
1949 va_start( args
, inFormat
);
1950 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
1953 dlog( kDebugLevelInfo
, "%s\n", buffer
);
1957 //===========================================================================================================================
1959 //===========================================================================================================================
1961 #if( MDNS_DEBUGMSGS > 1 )
1962 void verbosedebugf_( const char *inFormat
, ... )
1968 va_start( args
, inFormat
);
1969 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
1972 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
1976 //===========================================================================================================================
1978 //===========================================================================================================================
1981 void LogMsg( const char *inFormat, ... )
1987 va_start( args, inFormat );
1988 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
1991 dlog( kDebugLevelWarning, "%s\n", buffer );
1997 #pragma mark == Platform Internals ==
2000 //===========================================================================================================================
2001 // SetupSynchronizationObjects
2002 //===========================================================================================================================
2004 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
2008 InitializeCriticalSection( &inMDNS
->p
->lock
);
2009 inMDNS
->p
->lockInitialized
= mDNStrue
;
2011 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2012 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2013 require_noerr( err
, exit
);
2015 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2016 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2017 require_noerr( err
, exit
);
2019 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2020 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2021 require_noerr( err
, exit
);
2023 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2024 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2025 require_noerr( err
, exit
);
2030 TearDownSynchronizationObjects( inMDNS
);
2035 //===========================================================================================================================
2036 // TearDownSynchronizationObjects
2037 //===========================================================================================================================
2039 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
2041 if( inMDNS
->p
->quitEvent
)
2043 CloseHandle( inMDNS
->p
->quitEvent
);
2044 inMDNS
->p
->quitEvent
= 0;
2046 if( inMDNS
->p
->cancelEvent
)
2048 CloseHandle( inMDNS
->p
->cancelEvent
);
2049 inMDNS
->p
->cancelEvent
= 0;
2051 if( inMDNS
->p
->interfaceListChangedEvent
)
2053 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
2054 inMDNS
->p
->interfaceListChangedEvent
= 0;
2056 if( inMDNS
->p
->wakeupEvent
)
2058 CloseHandle( inMDNS
->p
->wakeupEvent
);
2059 inMDNS
->p
->wakeupEvent
= 0;
2061 if( inMDNS
->p
->lockInitialized
)
2063 DeleteCriticalSection( &inMDNS
->p
->lock
);
2064 inMDNS
->p
->lockInitialized
= mDNSfalse
;
2066 return( mStatus_NoError
);
2070 //===========================================================================================================================
2072 //===========================================================================================================================
2074 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
)
2077 char tempString
[ 256 ];
2082 // Set up the nice name.
2083 tempString
[ 0 ] = '\0';
2086 // First try and open the registry key that contains the computer description value
2087 if (inMDNS
->p
->descKey
== NULL
)
2089 LPCTSTR s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2090 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &inMDNS
->p
->descKey
);
2091 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2095 inMDNS
->p
->descKey
= NULL
;
2099 // if we opened it...
2100 if (inMDNS
->p
->descKey
!= NULL
)
2103 DWORD descSize
= sizeof( desc
);
2105 // look for the computer description
2106 err
= RegQueryValueEx(inMDNS
->p
->descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2110 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2119 // if we can't find it in the registry, then use the hostname of the machine
2120 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2122 err
= gethostname( tempString
, sizeof( tempString
) - 1 );
2123 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2127 err
= WindowsLatin1toUTF8( tempString
, utf8
, sizeof( utf8
) );
2136 // if we can't get the hostname
2137 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2139 // Invalidate name so fall back to a default name.
2141 strcpy( utf8
, kMDNSDefaultName
);
2144 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2145 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2146 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2148 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2154 //===========================================================================================================================
2156 //===========================================================================================================================
2158 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2161 char tempString
[ 256 ];
2162 domainlabel tempLabel
;
2166 // Set up the nice name.
2167 tempString
[ 0 ] = '\0';
2169 // use the hostname of the machine
2170 err
= gethostname( tempString
, sizeof( tempString
) - 1 );
2171 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2173 // if we can't get the hostname
2174 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2176 // Invalidate name so fall back to a default name.
2178 strcpy( tempString
, kMDNSDefaultName
);
2181 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2182 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2183 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2185 // Set up the host name.
2187 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2188 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2190 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2192 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2195 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2197 mDNS_SetFQDN( inMDNS
);
2199 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2204 //===========================================================================================================================
2206 //===========================================================================================================================
2208 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2214 err
= SetupNiceName( inMDNS
);
2217 err
= SetupHostName( inMDNS
);
2224 //===========================================================================================================================
2225 // SetupInterfaceList
2226 //===========================================================================================================================
2228 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2231 mDNSInterfaceData
** next
;
2232 mDNSInterfaceData
* ifd
;
2233 struct ifaddrs
* addrs
;
2235 struct ifaddrs
* loopback
;
2238 BOOL foundUnicastSock4DestAddr
;
2239 BOOL foundUnicastSock6DestAddr
;
2241 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2246 foundUnicastSock4DestAddr
= FALSE
;
2247 foundUnicastSock6DestAddr
= FALSE
;
2249 // Tear down any existing interfaces that may be set up.
2251 TearDownInterfaceList( inMDNS
);
2253 // Set up the name of this machine.
2255 err
= SetupName( inMDNS
);
2258 // Set up the interface list change notification.
2260 err
= SetupNotifications( inMDNS
);
2263 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2264 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2266 err
= getifaddrs( &addrs
);
2267 require_noerr( err
, exit
);
2270 next
= &inMDNS
->p
->interfaceList
;
2272 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_POINTTOPOINT
;
2273 flagTest
= IFF_UP
| IFF_MULTICAST
;
2275 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2276 for( p
= addrs
; p
; p
= p
->ifa_next
)
2278 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2282 if( p
->ifa_flags
& IFF_LOOPBACK
)
2290 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2291 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2293 err
= SetupInterface( inMDNS
, p
, &ifd
);
2294 require_noerr( err
, exit
);
2296 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2297 // of determing the destination address of a packet that is sent to us.
2298 // For multicast packets, that's easy to determine. But for the unicast
2299 // sockets, we'll fake it by taking the address of the first interface
2300 // that is successfully setup.
2302 if ( !foundUnicastSock4DestAddr
)
2304 inMDNS
->p
->unicastSock4DestAddr
= ifd
->interfaceInfo
.ip
;
2305 foundUnicastSock4DestAddr
= TRUE
;
2310 ++inMDNS
->p
->interfaceCount
;
2316 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2318 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2319 for( p
= addrs
; p
; p
= p
->ifa_next
)
2321 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2325 if( p
->ifa_flags
& IFF_LOOPBACK
)
2333 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2334 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2336 err
= SetupInterface( inMDNS
, p
, &ifd
);
2337 require_noerr( err
, exit
);
2339 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2340 // of determing the destination address of a packet that is sent to us.
2341 // For multicast packets, that's easy to determine. But for the unicast
2342 // sockets, we'll fake it by taking the address of the first interface
2343 // that is successfully setup.
2345 if ( !foundUnicastSock6DestAddr
)
2347 inMDNS
->p
->unicastSock6DestAddr
= ifd
->interfaceInfo
.ip
;
2348 foundUnicastSock6DestAddr
= TRUE
;
2353 ++inMDNS
->p
->interfaceCount
;
2357 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2359 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2361 flagMask
|= IFF_LOOPBACK
;
2362 flagTest
|= IFF_LOOPBACK
;
2364 for( p
= addrs
; p
; p
= p
->ifa_next
)
2366 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2370 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2380 if( !inMDNS
->p
->interfaceList
&& loopback
)
2382 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2383 loopback
->ifa_name
? loopback
->ifa_name
: "<null>", loopback
->ifa_extra
.index
, loopback
->ifa_addr
);
2385 err
= SetupInterface( inMDNS
, loopback
, &ifd
);
2386 require_noerr( err
, exit
);
2388 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2390 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2391 // of determing the destination address of a packet that is sent to us.
2392 // For multicast packets, that's easy to determine. But for the unicast
2393 // sockets, we'll fake it by taking the address of the first interface
2394 // that is successfully setup.
2396 if ( !foundUnicastSock4DestAddr
)
2398 inMDNS
->p
->unicastSock4DestAddr
= ifd
->defaultAddr
;
2399 foundUnicastSock4DestAddr
= TRUE
;
2405 ++inMDNS
->p
->interfaceCount
;
2411 TearDownInterfaceList( inMDNS
);
2415 freeifaddrs( addrs
);
2417 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2421 //===========================================================================================================================
2422 // TearDownInterfaceList
2423 //===========================================================================================================================
2425 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2428 mDNSInterfaceData
** p
;
2429 mDNSInterfaceData
* ifd
;
2431 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2435 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2436 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2437 // so that remove events that occur after an interface goes away can still report the correct interface.
2439 p
= &inMDNS
->p
->inactiveInterfaceList
;
2443 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2449 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2454 // Tear down interface list change notifications.
2456 err
= TearDownNotifications( inMDNS
);
2459 // Tear down all the interfaces.
2461 while( inMDNS
->p
->interfaceList
)
2463 ifd
= inMDNS
->p
->interfaceList
;
2464 inMDNS
->p
->interfaceList
= ifd
->next
;
2466 TearDownInterface( inMDNS
, ifd
);
2468 inMDNS
->p
->interfaceCount
= 0;
2470 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2471 return( mStatus_NoError
);
2474 //===========================================================================================================================
2476 //===========================================================================================================================
2478 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2480 mDNSInterfaceData
* ifd
;
2481 mDNSInterfaceData
* p
;
2486 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2490 check( inIFA
->ifa_addr
);
2493 // Allocate memory for the interface and initialize it.
2495 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2496 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2497 ifd
->sock
= kInvalidSocketRef
;
2498 ifd
->index
= inIFA
->ifa_extra
.index
;
2499 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2501 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2502 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2503 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2505 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2506 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2508 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2509 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2510 // on a large configured network, which means there's a good chance that most or all the other devices on that
2511 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2512 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2513 // devices on a large configured network, so we are willing to make that sacrifice.
2515 ifd
->interfaceInfo
.McastTxRx
= mDNStrue
;
2516 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2518 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2520 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2522 if (!ifd
->interfaceInfo
.InterfaceID
)
2524 p
->scopeID
= ifd
->scopeID
;
2525 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2528 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2529 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2530 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2532 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2539 if ( !ifd
->interfaceInfo
.InterfaceID
)
2541 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2544 // Set up a socket for this interface (if needed).
2546 if( ifd
->interfaceInfo
.McastTxRx
)
2548 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &sock
);
2549 require_noerr( err
, exit
);
2551 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2553 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2555 #if( !TARGET_OS_WINDOWS_CE )
2559 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
2560 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
2563 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
2568 // Set up the read pending event and associate it so we can block until data is available for this socket.
2570 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2571 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2572 require_noerr( err
, exit
);
2574 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
2575 require_noerr( err
, exit
);
2579 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2581 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2582 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2583 require_noerr( err
, exit
);
2586 // Register this interface with mDNS.
2588 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2589 require_noerr( err
, exit
);
2591 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2592 require_noerr( err
, exit
);
2594 ifd
->interfaceInfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
2596 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, 0 );
2597 require_noerr( err
, exit
);
2598 ifd
->hostRegistered
= mDNStrue
;
2600 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2610 TearDownInterface( inMDNS
, ifd
);
2612 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2616 //===========================================================================================================================
2617 // TearDownInterface
2618 //===========================================================================================================================
2620 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2627 // Deregister this interface with mDNS.
2629 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2631 if( inIFD
->hostRegistered
)
2633 inIFD
->hostRegistered
= mDNSfalse
;
2634 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
);
2637 // Tear down the multicast socket.
2639 if( inIFD
->readPendingEvent
)
2641 CloseHandle( inIFD
->readPendingEvent
);
2642 inIFD
->readPendingEvent
= 0;
2646 inIFD
->sock
= kInvalidSocketRef
;
2647 if( IsValidSocket( sock
) )
2649 close_compat( sock
);
2652 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2653 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2655 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2657 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2658 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2659 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2663 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2666 return( mStatus_NoError
);
2669 //===========================================================================================================================
2671 //===========================================================================================================================
2673 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2679 DEBUG_UNUSED( inMDNS
);
2681 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2683 check( outSocketRef
);
2685 // Set up an IPv4 or IPv6 UDP socket.
2687 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2688 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2689 require_noerr( err
, exit
);
2691 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2692 // if we're creating a multicast socket
2694 if ( port
.NotAnInteger
)
2697 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2698 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2701 if( inAddr
->sa_family
== AF_INET
)
2704 struct sockaddr_in sa4
;
2705 struct ip_mreq mreqv4
;
2707 // Bind the socket to the desired port
2709 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2710 memset( &sa4
, 0, sizeof( sa4
) );
2711 sa4
.sin_family
= AF_INET
;
2712 sa4
.sin_port
= port
.NotAnInteger
;
2713 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2715 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2716 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2718 // Turn on option to receive destination addresses and receiving interface.
2721 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2722 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2724 if (port
.NotAnInteger
)
2726 // Join the all-DNS multicast group so we receive Multicast DNS packets
2728 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
2729 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
2730 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
2731 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2733 // Specify the interface to send multicast packets on this socket.
2735 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2736 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
2737 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2739 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2742 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2743 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2746 // Send unicast packets with TTL 255 (helps against spoofing).
2749 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
2750 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2752 // Send multicast packets with TTL 255 (helps against spoofing).
2755 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
2756 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2759 else if( inAddr
->sa_family
== AF_INET6
)
2761 struct sockaddr_in6
* sa6p
;
2762 struct sockaddr_in6 sa6
;
2763 struct ipv6_mreq mreqv6
;
2765 sa6p
= (struct sockaddr_in6
*) inAddr
;
2767 // Bind the socket to the desired port
2769 memset( &sa6
, 0, sizeof( sa6
) );
2770 sa6
.sin6_family
= AF_INET6
;
2771 sa6
.sin6_port
= port
.NotAnInteger
;
2772 sa6
.sin6_flowinfo
= 0;
2773 sa6
.sin6_addr
= sa6p
->sin6_addr
;
2774 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
2776 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
2777 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2779 // Turn on option to receive destination addresses and receiving interface.
2782 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
2783 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2785 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
2786 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
2787 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
2789 #if( defined( IPV6_V6ONLY ) )
2791 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
2792 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2795 if ( port
.NotAnInteger
)
2797 // Join the all-DNS multicast group so we receive Multicast DNS packets.
2799 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroupv6
);
2800 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
2801 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
2802 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2804 // Specify the interface to send multicast packets on this socket.
2806 option
= (int) sa6p
->sin6_scope_id
;
2807 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
2808 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2810 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2813 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2814 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2817 // Send unicast packets with TTL 255 (helps against spoofing).
2820 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
2821 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2823 // Send multicast packets with TTL 255 (helps against spoofing).
2826 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
2827 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2831 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
2832 err
= kUnsupportedErr
;
2838 *outSocketRef
= sock
;
2839 sock
= kInvalidSocketRef
;
2840 err
= mStatus_NoError
;
2843 if( IsValidSocket( sock
) )
2845 close_compat( sock
);
2850 //===========================================================================================================================
2852 //===========================================================================================================================
2854 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
2861 if( inSA
->sa_family
== AF_INET
)
2863 struct sockaddr_in
* sa4
;
2865 sa4
= (struct sockaddr_in
*) inSA
;
2866 outIP
->type
= mDNSAddrType_IPv4
;
2867 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
2870 outPort
->NotAnInteger
= sa4
->sin_port
;
2872 err
= mStatus_NoError
;
2874 else if( inSA
->sa_family
== AF_INET6
)
2876 struct sockaddr_in6
* sa6
;
2878 sa6
= (struct sockaddr_in6
*) inSA
;
2879 outIP
->type
= mDNSAddrType_IPv6
;
2880 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
2881 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
2883 outIP
->ip
.v6
.w
[ 1 ] = 0;
2887 outPort
->NotAnInteger
= sa6
->sin6_port
;
2889 err
= mStatus_NoError
;
2893 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
2894 err
= mStatus_BadParamErr
;
2899 //===========================================================================================================================
2900 // SetupNotifications
2901 //===========================================================================================================================
2903 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
2907 unsigned long param
;
2912 // Register to listen for address list changes.
2914 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2915 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2916 require_noerr( err
, exit
);
2917 inMDNS
->p
->interfaceListChangedSocket
= sock
;
2919 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
2920 // when a change to the interface list is detected.
2923 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
2924 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
2925 require_noerr( err
, exit
);
2929 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
2932 check( errno_compat() == WSAEWOULDBLOCK
);
2935 err
= WSAEventSelect( sock
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
2936 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
2937 require_noerr( err
, exit
);
2939 inMDNS
->p
->descChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
2940 err
= translate_errno( inMDNS
->p
->descChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2941 require_noerr( err
, exit
);
2943 if (inMDNS
->p
->descKey
!= NULL
)
2945 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
2946 require_noerr( err
, exit
);
2949 // This will catch all changes to tcp/ip networking, including changes to the domain search list
2951 inMDNS
->p
->tcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
2952 err
= translate_errno( inMDNS
->p
->tcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2953 require_noerr( err
, exit
);
2955 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS
->p
->tcpipKey
);
2956 require_noerr( err
, exit
);
2958 err
= RegNotifyChangeKeyValue(inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
2959 require_noerr( err
, exit
);
2961 // This will catch all changes to ddns configuration
2963 inMDNS
->p
->ddnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
2964 err
= translate_errno( inMDNS
->p
->ddnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2965 require_noerr( err
, exit
);
2967 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup"), &inMDNS
->p
->ddnsKey
);
2968 require_noerr( err
, exit
);
2970 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
2971 require_noerr( err
, exit
);
2976 TearDownNotifications( inMDNS
);
2981 //===========================================================================================================================
2982 // TearDownNotifications
2983 //===========================================================================================================================
2985 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
2987 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
2989 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
2990 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
2993 if ( inMDNS
->p
->descChangedEvent
!= NULL
)
2995 CloseHandle( inMDNS
->p
->descChangedEvent
);
2996 inMDNS
->p
->descChangedEvent
= NULL
;
2999 if ( inMDNS
->p
->descKey
!= NULL
)
3001 RegCloseKey( inMDNS
->p
->descKey
);
3002 inMDNS
->p
->descKey
= NULL
;
3005 if ( inMDNS
->p
->tcpipChangedEvent
!= NULL
)
3007 CloseHandle( inMDNS
->p
->tcpipChangedEvent
);
3008 inMDNS
->p
->tcpipChangedEvent
= NULL
;
3011 if ( inMDNS
->p
->ddnsChangedEvent
!= NULL
)
3013 CloseHandle( inMDNS
->p
->ddnsChangedEvent
);
3014 inMDNS
->p
->ddnsChangedEvent
= NULL
;
3017 if ( inMDNS
->p
->ddnsKey
!= NULL
)
3019 RegCloseKey( inMDNS
->p
->ddnsKey
);
3020 inMDNS
->p
->ddnsKey
= NULL
;
3023 return( mStatus_NoError
);
3030 //===========================================================================================================================
3032 //===========================================================================================================================
3034 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
3037 HANDLE threadHandle
;
3041 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
3043 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3044 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3046 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3047 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3048 require_noerr( err
, exit
);
3050 inMDNS
->p
->initStatus
= mStatus_Invalid
;
3052 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3053 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3055 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
3056 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
3057 require_noerr( err
, exit
);
3059 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
3060 err
= translate_errno( result
== WAIT_OBJECT_0
, (mStatus
) GetLastError(), kUnknownErr
);
3061 require_noerr( err
, exit
);
3062 err
= inMDNS
->p
->initStatus
;
3063 require_noerr( err
, exit
);
3066 if( inMDNS
->p
->initEvent
)
3068 CloseHandle( inMDNS
->p
->initEvent
);
3069 inMDNS
->p
->initEvent
= 0;
3071 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
3075 //===========================================================================================================================
3077 //===========================================================================================================================
3079 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
3081 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3082 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3084 if( inMDNS
->p
->cancelEvent
)
3089 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
3090 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3092 if( inMDNS
->p
->quitEvent
)
3094 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
3095 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
3098 return( mStatus_NoError
);
3101 //===========================================================================================================================
3103 //===========================================================================================================================
3105 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
3117 m
= (mDNS
*) inParam
;
3118 err
= ProcessingThreadInitialize( m
);
3119 require_noerr( err
, exit
);
3124 // Set up the list of objects we'll be waiting on.
3128 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
3129 require_noerr( err
, exit
);
3131 // Main processing loop.
3133 gWaitListChanged
= FALSE
;
3137 // Give the mDNS core a chance to do its work and determine next event time.
3139 mDNSs32 interval
= mDNS_Execute(m
) - mDNS_TimeNow(m
);
3141 if ( gWaitListChanged
)
3146 if (m
->p
->idleThreadCallback
)
3148 interval
= m
->p
->idleThreadCallback(m
, interval
);
3150 if (interval
< 0) interval
= 0;
3151 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
3152 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
3154 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3156 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
3157 if( result
== WAIT_TIMEOUT
)
3159 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3161 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
3164 else if( result
== kWaitListCancelEvent
)
3166 // Cancel event. Set the done flag and break to exit.
3168 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
3172 else if( result
== kWaitListInterfaceListChangedEvent
)
3174 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3176 ProcessingThreadInterfaceListChanged( m
);
3179 else if( result
== kWaitListWakeupEvent
)
3181 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3183 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
3186 else if ( result
== kWaitListComputerDescriptionEvent
)
3189 // The computer description might have changed
3191 ProcessingThreadComputerDescriptionChanged( m
);
3194 else if ( result
== kWaitListTCPIPEvent
)
3197 // The TCP/IP might have changed
3199 ProcessingThreadTCPIPConfigChanged( m
);
3202 else if ( result
== kWaitListDynDNSEvent
)
3205 // The DynDNS config might have changed
3207 ProcessingThreadDynDNSConfigChanged( m
);
3214 // Socket data available event. Determine which socket and process the packet.
3216 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
3217 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
3218 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
3219 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
3221 HANDLE signaledObject
;
3223 mDNSInterfaceData
* ifd
;
3224 mDNSTCPConnectionData
* tcd
;
3226 signaledObject
= waitList
[ waitItemIndex
];
3228 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3229 if ( m
->p
->unicastSock4ReadEvent
== signaledObject
)
3231 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock4
);
3236 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3237 if ( m
->p
->unicastSock6ReadEvent
== signaledObject
)
3239 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock6
);
3244 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3246 if( ifd
->readPendingEvent
== signaledObject
)
3248 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
3253 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3255 if ( tcd
->pendingEvent
== signaledObject
)
3257 mDNSBool connect
= FALSE
;
3259 if ( !tcd
->connected
)
3261 tcd
->connected
= mDNStrue
;
3265 tcd
->callback( ( int ) tcd
->sock
, tcd
->context
, connect
);
3277 // Unexpected wait result.
3279 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
3284 // Release the wait list.
3294 // Signal the quit event to indicate that the thread is finished.
3297 wasSet
= SetEvent( m
->p
->quitEvent
);
3298 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3300 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3301 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3303 _endthreadex_compat( 0 );
3307 //===========================================================================================================================
3308 // ProcessingThreadInitialize
3309 //===========================================================================================================================
3311 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
3316 inMDNS
->p
->threadID
= GetCurrentThreadId();
3318 err
= SetupInterfaceList( inMDNS
);
3319 require_noerr( err
, exit
);
3321 err
= dDNS_Setup( inMDNS
);
3322 require_noerr( err
, exit
);
3324 err
= dDNS_InitDNSConfig( inMDNS
);
3325 require_noerr( err
, exit
);
3331 TearDownInterfaceList( inMDNS
);
3333 inMDNS
->p
->initStatus
= err
;
3335 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
3336 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3340 //===========================================================================================================================
3341 // ProcessingThreadSetupWaitList
3342 //===========================================================================================================================
3344 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
3349 HANDLE
* waitItemPtr
;
3350 mDNSInterfaceData
* ifd
;
3351 mDNSTCPConnectionData
* tcd
;
3353 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
3356 check( outWaitList
);
3357 check( outWaitListCount
);
3359 // Allocate an array to hold all the objects to wait on.
3361 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->interfaceCount
+ gTCPConnections
;
3362 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
3363 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
3364 waitItemPtr
= waitList
;
3366 // Add the fixed wait items to the beginning of the list.
3368 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
3369 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
3370 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
3371 *waitItemPtr
++ = inMDNS
->p
->descChangedEvent
;
3372 *waitItemPtr
++ = inMDNS
->p
->tcpipChangedEvent
;
3373 *waitItemPtr
++ = inMDNS
->p
->ddnsChangedEvent
;
3375 // Append all the dynamic wait items to the list.
3376 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3377 *waitItemPtr
++ = inMDNS
->p
->unicastSock4ReadEvent
;
3380 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3381 *waitItemPtr
++ = inMDNS
->p
->unicastSock6ReadEvent
;
3384 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3386 *waitItemPtr
++ = ifd
->readPendingEvent
;
3389 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3391 *waitItemPtr
++ = tcd
->pendingEvent
;
3394 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
3396 *outWaitList
= waitList
;
3397 *outWaitListCount
= waitListCount
;
3399 err
= mStatus_NoError
;
3406 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
3410 //===========================================================================================================================
3411 // ProcessingThreadProcessPacket
3412 //===========================================================================================================================
3414 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
)
3417 const mDNSInterfaceID iid
= inIFD
? inIFD
->interfaceInfo
.InterfaceID
: NULL
;
3418 LPFN_WSARECVMSG recvMsgPtr
;
3424 struct sockaddr_storage addr
;
3430 check( IsValidSocket( inSock
) );
3432 // Set up the default in case the packet info options are not supported or reported correctly.
3436 recvMsgPtr
= inIFD
->wsaRecvMsgFunctionPtr
;
3437 dstAddr
= inIFD
->defaultAddr
;
3438 dstPort
= MulticastDNSPort
;
3441 else if ( inSock
== inMDNS
->p
->unicastSock4
)
3443 recvMsgPtr
= inMDNS
->p
->unicastSock4RecvMsgPtr
;
3444 dstAddr
= inMDNS
->p
->unicastSock4DestAddr
;
3445 dstPort
= zeroIPPort
;
3448 else if ( inSock
== inMDNS
->p
->unicastSock6
)
3450 recvMsgPtr
= inMDNS
->p
->unicastSock6RecvMsgPtr
;
3451 dstAddr
= inMDNS
->p
->unicastSock6DestAddr
;
3452 dstPort
= zeroIPPort
;
3457 dlog( kDebugLevelError
, DEBUG_NAME
"packet received on unknown socket\n" );
3461 #if( !TARGET_OS_WINDOWS_CE )
3466 uint8_t controlBuffer
[ 128 ];
3468 LPWSACMSGHDR header
;
3470 // Set up the buffer and read the packet.
3472 msg
.name
= (LPSOCKADDR
) &addr
;
3473 msg
.namelen
= (INT
) sizeof( addr
);
3474 buf
.buf
= (char *) &packet
;
3475 buf
.len
= (u_long
) sizeof( packet
);
3476 msg
.lpBuffers
= &buf
;
3477 msg
.dwBufferCount
= 1;
3478 msg
.Control
.buf
= (char *) controlBuffer
;
3479 msg
.Control
.len
= (u_long
) sizeof( controlBuffer
);
3482 err
= recvMsgPtr( inSock
, &msg
, &size
, NULL
, NULL
);
3483 err
= translate_errno( err
== 0, (OSStatus
) GetLastError(), kUnknownErr
);
3484 require_noerr( err
, exit
);
3487 // Parse the control information. Reject packets received on the wrong interface.
3489 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
3491 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3493 IN_PKTINFO
* ipv4PacketInfo
;
3495 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3499 require_action( ipv4PacketInfo
->ipi_ifindex
== ( inIFD
->index
>> 8 ), exit
, err
= kMismatchErr
);
3502 dstAddr
.type
= mDNSAddrType_IPv4
;
3503 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3505 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3507 IN6_PKTINFO
* ipv6PacketInfo
;
3509 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3513 require_action( ipv6PacketInfo
->ipi6_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
3516 dstAddr
.type
= mDNSAddrType_IPv6
;
3517 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3526 addrSize
= sizeof( addr
);
3527 n
= recvfrom( inSock
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
3528 err
= translate_errno( n
> 0, errno_compat(), kUnknownErr
);
3529 require_noerr( err
, exit
);
3531 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
3533 // Dispatch the packet to mDNS.
3535 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3536 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
3537 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3538 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3542 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &inIFD
->interfaceInfo
.ip
, (int) inIFD
->index
);
3545 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3547 end
= ( (mDNSu8
*) &packet
) + n
;
3548 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3554 //===========================================================================================================================
3555 // ProcessingThreadInterfaceListChanged
3556 //===========================================================================================================================
3558 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
3562 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3565 if (inMDNS
->p
->interfaceListChangedCallback
)
3567 inMDNS
->p
->interfaceListChangedCallback(inMDNS
);
3570 mDNSPlatformLock( inMDNS
);
3572 // Tear down the existing interfaces and set up new ones using the new IP info.
3574 err
= TearDownInterfaceList( inMDNS
);
3577 err
= SetupInterfaceList( inMDNS
);
3580 mDNSPlatformUnlock( inMDNS
);
3582 // Inform clients of the change.
3584 if( inMDNS
->MainCallback
)
3586 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
3589 // Force mDNS to update.
3591 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
3595 //===========================================================================================================================
3596 // ProcessingThreadComputerDescriptionChanged
3597 //===========================================================================================================================
3598 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
*inMDNS
)
3602 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3605 mDNSPlatformLock( inMDNS
);
3608 SetupNiceName( inMDNS
);
3610 if (inMDNS
->p
->hostDescriptionChangedCallback
)
3612 inMDNS
->p
->hostDescriptionChangedCallback(inMDNS
);
3615 // and reset the event handler
3616 if ((inMDNS
->p
->descKey
!= NULL
) && (inMDNS
->p
->descChangedEvent
))
3618 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3622 mDNSPlatformUnlock( inMDNS
);
3626 //===========================================================================================================================
3627 // ProcessingThreadTCPIPConfigChanged
3628 //===========================================================================================================================
3629 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
)
3633 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3636 mDNSPlatformLock( inMDNS
);
3638 err
= dDNS_Setup( inMDNS
);
3641 // and reset the event handler
3643 if ( ( inMDNS
->p
->tcpipKey
!= NULL
) && ( inMDNS
->p
->tcpipChangedEvent
) )
3645 err
= RegNotifyChangeKeyValue( inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3649 mDNSPlatformUnlock( inMDNS
);
3653 //===========================================================================================================================
3654 // ProcessingThreadDynDNSConfigChanged
3655 //===========================================================================================================================
3656 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
*inMDNS
)
3660 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3663 mDNSPlatformLock( inMDNS
);
3665 err
= dDNS_Setup( inMDNS
);
3668 // and reset the event handler
3670 if ((inMDNS
->p
->ddnsKey
!= NULL
) && (inMDNS
->p
->ddnsChangedEvent
))
3672 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3676 mDNSPlatformUnlock( inMDNS
);
3682 #pragma mark == Utilities ==
3685 //===========================================================================================================================
3687 //===========================================================================================================================
3689 int getifaddrs( struct ifaddrs
**outAddrs
)
3693 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
3695 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3696 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3698 if( !gIPHelperLibraryInstance
)
3700 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
3701 if( gIPHelperLibraryInstance
)
3703 gGetAdaptersAddressesFunctionPtr
=
3704 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
3705 if( !gGetAdaptersAddressesFunctionPtr
)
3709 ok
= FreeLibrary( gIPHelperLibraryInstance
);
3710 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
3711 gIPHelperLibraryInstance
= NULL
;
3716 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3718 if( gGetAdaptersAddressesFunctionPtr
)
3720 err
= getifaddrs_ipv6( outAddrs
);
3721 require_noerr( err
, exit
);
3725 err
= getifaddrs_ipv4( outAddrs
);
3726 require_noerr( err
, exit
);
3729 #elif( !TARGET_OS_WINDOWS_CE )
3731 err
= getifaddrs_ipv4( outAddrs
);
3732 require_noerr( err
, exit
);
3736 err
= getifaddrs_ce( outAddrs
);
3737 require_noerr( err
, exit
);
3745 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3746 //===========================================================================================================================
3748 //===========================================================================================================================
3750 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
3755 struct ifaddrs
* head
;
3756 struct ifaddrs
** next
;
3757 IP_ADAPTER_ADDRESSES
* iaaList
;
3759 IP_ADAPTER_ADDRESSES
* iaa
;
3761 struct ifaddrs
* ifa
;
3763 check( gGetAdaptersAddressesFunctionPtr
);
3769 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3770 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3771 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3773 flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
3778 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
3779 check( err
== ERROR_BUFFER_OVERFLOW
);
3780 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
3782 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
3783 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
3785 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
3786 if( err
== ERROR_SUCCESS
) break;
3791 require( i
< 100, exit
);
3792 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
3795 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
3798 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
3800 IP_ADAPTER_PREFIX
* firstPrefix
;
3802 if( iaa
->IfIndex
> 0xFFFFFF )
3804 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
3806 if( iaa
->Ipv6IfIndex
> 0xFF )
3808 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
3811 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3812 // following code to crash when iterating through the prefix list. This seems
3813 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3814 // This shouldn't happen according to Microsoft docs which states:
3816 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3818 // So the data structure seems to be corrupted when we return from
3819 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3820 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3821 // modify iaa to have the correct values.
3823 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
3825 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
3826 firstPrefix
= iaa
->FirstPrefix
;
3834 // Skip psuedo and tunnel interfaces.
3836 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
3841 // Add each address as a separate interface to emulate the way getifaddrs works.
3843 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
3847 IP_ADAPTER_PREFIX
* prefix
;
3850 family
= addr
->Address
.lpSockaddr
->sa_family
;
3851 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
3853 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3854 require_action( ifa
, exit
, err
= WSAENOBUFS
);
3857 next
= &ifa
->ifa_next
;
3861 size
= strlen( iaa
->AdapterName
) + 1;
3862 ifa
->ifa_name
= (char *) malloc( size
);
3863 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
3864 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
3866 // Get interface flags.
3869 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
3870 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
3871 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
3873 // Get the interface index. Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes
3874 // so the following is a hack to put IPv4 interface indexes in the upper 24-bits and IPv6 interface indexes
3875 // in the lower 8-bits. This allows the IPv6 interface index to be usable as an IPv6 scope ID directly.
3879 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
<< 8; break;
3880 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
; break;
3890 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
3891 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
3892 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
3898 check( ifa
->ifa_addr
);
3900 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
3903 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
3905 if( prefixIndex
== addrIndex
)
3907 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
3908 prefixLength
= prefix
->PrefixLength
;
3916 struct sockaddr_in
* sa4
;
3918 require_action( prefixLength
<= 32, exit
, err
= ERROR_INVALID_DATA
);
3920 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
3921 require_action( sa4
, exit
, err
= WSAENOBUFS
);
3923 sa4
->sin_family
= AF_INET
;
3924 if( prefixLength
== 0 )
3926 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv4 netmask 0, defaulting to 255.255.255.255\n", __ROUTINE__
);
3929 sa4
->sin_addr
.s_addr
= htonl( 0xFFFFFFFFU
<< ( 32 - prefixLength
) );
3930 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
3936 struct sockaddr_in6
* sa6
;
3941 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
3943 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
3944 require_action( sa6
, exit
, err
= WSAENOBUFS
);
3945 sa6
->sin6_family
= AF_INET6
;
3947 if( prefixLength
== 0 )
3949 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
3953 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
3955 if( len
>= 8 ) maskByte
= 0xFF;
3956 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
3957 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
3959 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
3976 err
= ERROR_SUCCESS
;
3981 freeifaddrs( head
);
3987 return( (int) err
);
3990 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
3992 #if( !TARGET_OS_WINDOWS_CE )
3993 //===========================================================================================================================
3995 //===========================================================================================================================
3997 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
4003 INTERFACE_INFO
* buffer
;
4004 INTERFACE_INFO
* tempBuffer
;
4005 INTERFACE_INFO
* ifInfo
;
4008 struct ifaddrs
* head
;
4009 struct ifaddrs
** next
;
4010 struct ifaddrs
* ifa
;
4012 sock
= INVALID_SOCKET
;
4017 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4018 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4019 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4021 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4022 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4023 require_noerr( err
, exit
);
4026 size
= 16 * sizeof( INTERFACE_INFO
);
4029 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
4030 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
4031 buffer
= tempBuffer
;
4033 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
4040 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
4042 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
4044 check( actualSize
<= size
);
4045 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
4046 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
4048 // Process the raw interface list and build a linked list of IPv4 interfaces.
4050 for( i
= 0; i
< n
; ++i
)
4052 ifInfo
= &buffer
[ i
];
4053 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
4058 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4059 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4062 next
= &ifa
->ifa_next
;
4066 ifa
->ifa_name
= (char *) malloc( 16 );
4067 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4068 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4070 // Get interface flags.
4072 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4076 switch( ifInfo
->iiAddress
.Address
.sa_family
)
4080 struct sockaddr_in
* sa4
;
4082 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4083 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4084 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4085 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4087 sa4
= &ifInfo
->iiNetmask
.AddressIn
;
4088 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4089 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4090 memcpy( ifa
->ifa_netmask
, sa4
, sizeof( *sa4
) );
4099 // Emulate an interface index.
4101 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4116 freeifaddrs( head
);
4122 if( sock
!= INVALID_SOCKET
)
4124 closesocket( sock
);
4128 #endif // !TARGET_OS_WINDOWS_CE )
4130 #if( TARGET_OS_WINDOWS_CE )
4131 //===========================================================================================================================
4133 //===========================================================================================================================
4135 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
4141 SOCKET_ADDRESS_LIST
* addressList
;
4142 struct ifaddrs
* head
;
4143 struct ifaddrs
** next
;
4144 struct ifaddrs
* ifa
;
4148 sock
= kInvalidSocketRef
;
4153 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4155 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4156 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4157 require_noerr( err
, exit
);
4159 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4160 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4162 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4165 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
4166 require_action( size
> 0, exit
, err
= -1 );
4169 buffer
= calloc( 1, size
);
4170 require_action( buffer
, exit
, err
= -1 );
4172 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4174 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
4175 require_noerr( err
, exit
);
4176 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
4178 // Process the raw interface list and build a linked list of interfaces.
4180 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4182 n
= addressList
->iAddressCount
;
4187 for( i
= 0; i
< n
; ++i
)
4189 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4190 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4193 next
= &ifa
->ifa_next
;
4197 ifa
->ifa_name
= (char *) malloc( 16 );
4198 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4199 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4201 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4203 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
4207 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
4211 struct sockaddr_in
* sa4
;
4213 sa4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
4214 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4215 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4216 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4237 freeifaddrs( head
);
4243 if( sock
!= INVALID_SOCKET
)
4245 closesocket( sock
);
4249 #endif // TARGET_OS_WINDOWS_CE )
4251 //===========================================================================================================================
4253 //===========================================================================================================================
4255 void freeifaddrs( struct ifaddrs
*inIFAs
)
4260 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4262 for( p
= inIFAs
; p
; p
= q
)
4268 free( p
->ifa_name
);
4273 free( p
->ifa_addr
);
4276 if( p
->ifa_netmask
)
4278 free( p
->ifa_netmask
);
4279 p
->ifa_netmask
= NULL
;
4281 if( p
->ifa_broadaddr
)
4283 free( p
->ifa_broadaddr
);
4284 p
->ifa_broadaddr
= NULL
;
4286 if( p
->ifa_dstaddr
)
4288 free( p
->ifa_dstaddr
);
4289 p
->ifa_dstaddr
= NULL
;
4293 free( p
->ifa_data
);
4300 //===========================================================================================================================
4301 // CanReceiveUnicast
4302 //===========================================================================================================================
4304 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4308 struct sockaddr_in addr
;
4310 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4312 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4313 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4314 ok
= IsValidSocket( sock
);
4317 memset( &addr
, 0, sizeof( addr
) );
4318 addr
.sin_family
= AF_INET
;
4319 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4320 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4322 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4323 close_compat( sock
);
4326 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4330 //===========================================================================================================================
4331 // GetWindowsVersionString
4332 //===========================================================================================================================
4334 OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4336 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4337 #define VER_PLATFORM_WIN32_CE 3
4341 OSVERSIONINFO osInfo
;
4343 const char * versionString
;
4349 versionString
= "unknown Windows version";
4351 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4352 ok
= GetVersionEx( &osInfo
);
4353 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4354 require_noerr( err
, exit
);
4356 platformID
= osInfo
.dwPlatformId
;
4357 majorVersion
= osInfo
.dwMajorVersion
;
4358 minorVersion
= osInfo
.dwMinorVersion
;
4359 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4361 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4363 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4365 versionString
= "Windows 95";
4367 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4369 versionString
= "Windows 95 SP1";
4371 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4373 versionString
= "Windows 95 OSR2";
4375 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4377 versionString
= "Windows 98";
4379 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4381 versionString
= "Windows 98 SP1";
4383 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4385 versionString
= "Windows 98 SE";
4387 else if( minorVersion
== 90 )
4389 versionString
= "Windows ME";
4392 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4394 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4396 versionString
= "Windows NT 3.51";
4398 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4400 versionString
= "Windows NT 4";
4402 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4404 versionString
= "Windows 2000";
4406 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4408 versionString
= "Windows XP";
4410 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4412 versionString
= "Windows Server 2003";
4415 else if( platformID
== VER_PLATFORM_WIN32_CE
)
4417 versionString
= "Windows CE";
4421 if( inBuffer
&& ( inBufferSize
> 0 ) )
4424 strncpy( inBuffer
, versionString
, inBufferSize
);
4425 inBuffer
[ inBufferSize
] = '\0';
4431 //===========================================================================================================================
4433 //===========================================================================================================================
4436 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
4442 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
4453 *string
= (char*) malloc( *stringLen
);
4454 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
4456 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
4460 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
4462 require_noerr_quiet( err
, exit
);
4466 DWORD dwSize
= sizeof( DWORD
);
4468 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
4480 //===========================================================================================================================
4482 //===========================================================================================================================
4484 static mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
4486 struct sockaddr_in6 sa6
;
4487 struct sockaddr_in sa4
;
4491 sa6
.sin6_family
= AF_INET6
;
4492 dwSize
= sizeof( sa6
);
4494 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
4496 if ( err
== mStatus_NoError
)
4498 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa6
);
4499 require_noerr( err
, exit
);
4503 sa4
.sin_family
= AF_INET
;
4504 dwSize
= sizeof( sa4
);
4506 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
4507 require_noerr( err
, exit
);
4509 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa4
);
4510 require_noerr( err
, exit
);
4519 //===========================================================================================================================
4521 //===========================================================================================================================
4523 mDNSlocal
struct ifaddrs
*
4524 myGetIfAddrs(int refresh
)
4526 static struct ifaddrs
*ifa
= NULL
;
4543 //===========================================================================================================================
4545 //===========================================================================================================================
4548 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
4550 #if( defined( UNICODE ) || defined( _UNICODE ) )
4554 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4555 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4556 require_noerr( err
, exit
);
4561 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
4566 //===========================================================================================================================
4567 // WindowsLatin1toUTF8
4568 //===========================================================================================================================
4571 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
4579 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4581 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
4582 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4583 require_noerr( err
, exit
);
4585 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
4586 require_action( utf16
, exit
, err
= kNoMemoryErr
);
4588 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
4589 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4590 require_noerr( err
, exit
);
4592 // Now convert the temporary UTF-16 to UTF-8.
4594 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4595 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4596 require_noerr( err
, exit
);
4599 if( utf16
) free( utf16
);
4604 //===========================================================================================================================
4605 // ConvertUTF8ToLsaString
4606 //===========================================================================================================================
4609 ConvertUTF8ToLsaString( const char * input
, PLSA_UNICODE_STRING output
)
4617 output
->Buffer
= NULL
;
4619 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, NULL
, 0 );
4620 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
4621 require_noerr( err
, exit
);
4623 output
->Length
= (USHORT
)( size
* sizeof( wchar_t ) );
4624 output
->Buffer
= (PWCHAR
) malloc( output
->Length
);
4625 require_action( output
->Buffer
, exit
, err
= mStatus_NoMemoryErr
);
4626 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, output
->Buffer
, size
);
4627 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
4628 require_noerr( err
, exit
);
4630 // We're going to subtrace one wchar_t from the size, because we didn't
4631 // include it when we encoded the string
4633 output
->MaximumLength
= output
->Length
;
4634 output
->Length
-= sizeof( wchar_t );
4638 if ( err
&& output
->Buffer
)
4640 free( output
->Buffer
);
4641 output
->Buffer
= NULL
;
4648 //===========================================================================================================================
4649 // ConvertLsaStringToUTF8
4650 //===========================================================================================================================
4653 ConvertLsaStringToUTF8( PLSA_UNICODE_STRING input
, char ** output
)
4656 OSStatus err
= kNoErr
;
4658 // The Length field of this structure holds the number of bytes,
4659 // but WideCharToMultiByte expects the number of wchar_t's. So
4660 // we divide by sizeof(wchar_t) to get the correct number.
4662 size
= WideCharToMultiByte(CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), NULL
, 0, NULL
, NULL
);
4663 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
4664 require_noerr( err
, exit
);
4666 // Add one for trailing '\0'
4668 *output
= (char*) malloc( size
+ 1 );
4669 require_action( *output
, exit
, err
= mStatus_NoMemoryErr
);
4671 size
= WideCharToMultiByte(CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), *output
, size
, NULL
, NULL
);
4672 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
4673 require_noerr( err
, exit
);
4675 // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
4676 // although it does return the correct size
4678 (*output
)[size
] = '\0';
4682 if ( err
&& *output
)
4692 //===========================================================================================================================
4693 // FreeTCPConnectionData
4694 //===========================================================================================================================
4697 FreeTCPConnectionData( mDNSTCPConnectionData
* data
)
4701 if ( data
->pendingEvent
)
4703 CloseHandle( data
->pendingEvent
);
4706 if ( data
->sock
!= INVALID_SOCKET
)
4708 closesocket( data
->sock
);