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.105 2005/11/27 20:21:16 herscher
27 <rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
29 Revision 1.104 2005/10/19 19:42:59 herscher
30 <rdar://problem/4295946> Use the registry to determine the domain name, rather than using GetNetworkParams(). GetNetworkParams() does not reliably return domain information for the current network configuration.
32 Revision 1.103 2005/10/18 06:13:20 herscher
33 <rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
35 Revision 1.102 2005/10/05 20:55:14 herscher
36 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
38 Revision 1.101 2005/10/05 18:05:28 herscher
39 <rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
41 Revision 1.100 2005/09/29 06:36:00 herscher
42 Change check( err ) to check( !err ). This was a typo that was introduced in a previous checkin.
44 Revision 1.99 2005/09/29 06:31:46 herscher
45 <rdar://problem/4278934> Fall back to calling getifaddrs_ipv4 if getifaddrs_ipv6 fails
47 Revision 1.98 2005/09/24 01:11:56 cheshire
48 Add comment about GetWindowsVersionString
50 Revision 1.97 2005/09/22 07:10:44 herscher
51 <rdar://problem/4263713> Don't send domain enumeration query if domain is empty string or "."
53 Revision 1.96 2005/09/22 07:06:06 herscher
54 <rdar://problem/4252581> Don't loop uncontrollably upon detection of error in main event loop
56 Revision 1.95 2005/09/11 22:51:40 herscher
57 <rdar://problem/4249284> Obtain Hostname by using GetComputerNameEx, rather than gethostname.
59 Revision 1.94 2005/09/11 21:43:15 herscher
60 <rdar://problem/4245949> Don't create HINFO records on Windows
62 Revision 1.93 2005/07/15 06:06:40 shersche
63 <rdar://problem/4165134> Change all WinSock allocation loops to bail out after 100 tries to eliminate the possibility of any infinite loops
65 Revision 1.92 2005/07/11 20:32:17 shersche
66 <rdar://problem/4175515> Fix crash when logging into Cisco VPN
68 Revision 1.91 2005/04/25 21:34:28 shersche
69 <rdar://problem/4096465> Wide-Area services don't disappear when interface goes away
71 Revision 1.90 2005/04/25 21:18:08 shersche
72 <rdar://problem/4097314> mDNSResponder crash when interface goes away. This error seems to be caused by the Windows platform code not returning mStatus_TransientErr when there is a problem with a udp unicast send.
74 Revision 1.89 2005/04/22 07:32:24 shersche
75 <rdar://problem/4092108> PPP connection disables Bonjour .local lookups
76 <rdar://problem/4093944> mDNSResponder ignores Point-to-Point interfaces
78 Revision 1.88 2005/04/05 03:53:03 shersche
79 <rdar://problem/4066485> Registering with shared secret key doesn't work.
81 Revision 1.87 2005/04/03 08:03:12 shersche
82 <rdar://problem/4076478> mDNSResponder won't start on Windows 2000.
84 Revision 1.86 2005/03/30 07:37:14 shersche
85 Use prefix to compute IPv4 subnet mask, falling back to calling AddressToIndexAndMask only if prefix is zero.
87 Revision 1.85 2005/03/30 07:34:52 shersche
88 <rdar://problem/4045657> Interface index being returned is 512
90 Revision 1.84 2005/03/29 19:19:47 shersche
91 <rdar://problem/4055599> Windows is not accepting unicast responses. This bug was a result of an error in obtaining the subnet mask for IPv4 interfaces.
93 Revision 1.83 2005/03/07 18:27:42 shersche
94 <rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
96 Revision 1.82 2005/03/06 05:20:24 shersche
97 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
99 Revision 1.81 2005/03/04 22:44:53 shersche
100 <rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
102 Revision 1.80 2005/03/03 21:07:38 shersche
103 <rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
105 Revision 1.79 2005/03/03 02:29:00 shersche
106 Use the RegNames.h header file for registry key names
108 Revision 1.78 2005/03/02 04:04:17 shersche
109 Support for multiple browse domains
111 Revision 1.77 2005/02/25 20:02:18 shersche
112 <rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
114 Revision 1.76 2005/02/23 02:59:20 shersche
115 <rdar://problem/4013482> Check to see if locks have been initialized before using them.
117 Revision 1.75 2005/02/16 02:36:25 shersche
118 <rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
120 Revision 1.74 2005/02/08 06:06:16 shersche
121 <rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
123 Revision 1.73 2005/02/01 19:35:43 ksekar
124 Removed obsolete arguments from mDNS_SetSecretForZone
126 Revision 1.72 2005/02/01 01:38:53 shersche
127 Handle null DynDNS configuration more gracefully
129 Revision 1.71 2005/01/27 22:57:57 cheshire
130 Fix compile errors on gcc4
132 Revision 1.70 2005/01/25 08:12:52 shersche
133 <rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
136 Revision 1.69 2005/01/11 04:39:48 shersche
137 Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
139 Revision 1.68 2005/01/11 02:04:48 shersche
140 Gracefully handle when IPv6 is not installed on a user's machine
142 Revision 1.67 2004/12/18 00:51:52 cheshire
143 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
145 Revision 1.66 2004/12/17 23:37:49 cheshire
146 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
147 (and other repetitive configuration changes)
149 Revision 1.65 2004/12/15 07:34:45 shersche
150 Add platform support for IPv4 and IPv6 unicast sockets
152 Revision 1.64 2004/12/15 06:06:15 shersche
153 Fix problem in obtaining IPv6 subnet mask
155 Revision 1.63 2004/11/23 03:39:47 cheshire
156 Let interface name/index mapping capability live directly in JNISupport.c,
157 instead of having to call through to the daemon via IPC to get this information.
159 Revision 1.62 2004/11/12 03:16:41 rpantos
160 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
162 Revision 1.61 2004/11/05 22:54:38 shersche
163 Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
164 Submitted by: Pavel Repin <prepin@gmail.com>
166 Revision 1.60 2004/11/05 22:41:56 shersche
167 Determine subnet mask when populating network interface data structures
168 Submitted by: Pavel Repin <prepin@gmail.com>
171 Revision 1.59 2004/10/28 03:24:42 cheshire
172 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
174 Revision 1.58 2004/10/16 00:17:01 cheshire
175 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
177 Revision 1.57 2004/10/11 21:53:15 shersche
178 <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().
181 Revision 1.56 2004/09/26 23:20:36 ksekar
182 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
184 Revision 1.55 2004/09/21 21:02:57 cheshire
185 Set up ifname before calling mDNS_RegisterInterface()
187 Revision 1.54 2004/09/17 01:08:57 cheshire
188 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
189 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
190 declared in that file are ONLY appropriate to single-address-space embedded applications.
191 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
193 Revision 1.53 2004/09/17 00:19:11 cheshire
194 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
196 Revision 1.52 2004/09/16 00:24:50 cheshire
197 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
199 Revision 1.51 2004/09/14 23:42:37 cheshire
200 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
202 Revision 1.50 2004/08/25 23:36:56 shersche
203 <rdar://problem/3658379> Remove code that retrieves TTL from received packets
206 Revision 1.49 2004/08/25 16:43:29 ksekar
207 Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
210 Revision 1.48 2004/08/14 03:22:43 cheshire
211 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
212 Add GetUserSpecifiedDDNSName() routine
213 Convert ServiceRegDomain to domainname instead of C string
214 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
216 Revision 1.47 2004/08/06 17:33:02 shersche
217 <rdar://problem/3753797> Put correct length of string in first byte of nicelabel
220 Revision 1.46 2004/08/05 05:43:01 shersche
221 <rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
224 Revision 1.45 2004/07/26 22:49:31 ksekar
225 <rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
227 Revision 1.44 2004/07/26 05:42:50 shersche
228 use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
230 Revision 1.43 2004/07/13 21:24:25 rpantos
231 Fix for <rdar://problem/3701120>.
233 Revision 1.42 2004/06/24 15:23:24 shersche
234 Add InterfaceListChanged callback. This callback is used in Service.c to add link local routes to the routing table
235 Submitted by: herscher
237 Revision 1.41 2004/06/18 05:22:16 rpantos
238 Integrate Scott's changes
240 Revision 1.40 2004/05/26 09:06:07 bradley
241 Retry while building the interface list if it returns an error since the two-step process required to
242 get the interface list could allow a subsequent interface change to come in that window and change the
243 needed size after getting the size, but before getting the list, causing it to return an error.
244 Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
246 Revision 1.39 2004/05/18 23:51:27 cheshire
247 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
249 Revision 1.38 2004/05/13 04:57:48 ksekar
250 Removed unnecessary FreeSearchList function
252 Revision 1.37 2004/05/13 04:54:20 ksekar
253 Unified list copy/free code. Added symetric list for
255 Revision 1.36 2004/05/12 22:03:09 ksekar
256 Made GetSearchDomainList a true platform-layer call (declaration moved
257 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
258 only on non-OSX platforms. Changed call to return a copy of the list
259 to avoid shared memory issues. Added a routine to free the list.
261 Revision 1.35 2004/04/21 02:49:12 cheshire
262 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
264 Revision 1.34 2004/04/15 01:00:05 bradley
265 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
266 without .local name resolving support will need to manually query for A/AAAA records as needed.
268 Revision 1.33 2004/04/14 23:09:29 ksekar
269 Support for TSIG signed dynamic updates.
271 Revision 1.32 2004/04/09 17:40:26 cheshire
272 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
274 Revision 1.31 2004/04/09 00:40:46 bradley
275 Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
277 Revision 1.30 2004/04/09 00:33:58 bradley
278 Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
280 Revision 1.29 2004/03/15 02:07:46 bradley
281 Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
282 handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
283 does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
285 Revision 1.28 2004/03/07 00:26:39 bradley
286 Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
287 Added count assert when building the wait list to catch underruns/overruns if the code is changed.
289 Revision 1.27 2004/01/30 02:44:32 bradley
290 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
291 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
292 are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
293 (it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
294 software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
295 reporting HINFO records with the Windows and mDNSResponder version information.
297 Revision 1.26 2004/01/24 04:59:16 cheshire
298 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
300 Revision 1.25 2003/11/14 20:59:09 cheshire
301 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
302 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
304 Revision 1.24 2003/10/24 23:23:02 bradley
305 Removed legacy port 53 support as it is no longer needed.
307 Revision 1.23 2003/10/14 03:26:12 bradley
308 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
310 Revision 1.22 2003/08/20 06:21:25 bradley
311 Updated to latest internal version of the mDNSWindows platform layer: Added support
312 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
313 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
314 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
315 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
316 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
317 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
318 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
319 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
321 Revision 1.21 2003/08/18 23:09:57 cheshire
322 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
324 Revision 1.20 2003/08/12 19:56:27 cheshire
327 Revision 1.19 2003/08/05 23:58:18 cheshire
328 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
329 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
331 Revision 1.18 2003/07/23 21:16:30 cheshire
332 Removed a couple of debugfs
334 Revision 1.17 2003/07/23 02:23:01 cheshire
335 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
336 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
338 Revision 1.16 2003/07/19 03:15:16 cheshire
339 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
340 and add the obvious trivial implementations to each platform support layer
342 Revision 1.15 2003/07/02 21:20:04 cheshire
343 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
345 Revision 1.14 2003/05/26 03:21:30 cheshire
346 Tidy up address structure naming:
347 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
348 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
349 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
351 Revision 1.13 2003/05/26 03:01:28 cheshire
352 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
354 Revision 1.12 2003/05/06 21:06:05 cheshire
355 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
357 Revision 1.11 2003/05/06 00:00:51 cheshire
358 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
360 Revision 1.10 2003/04/29 00:06:09 cheshire
361 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
363 Revision 1.9 2003/04/26 02:40:01 cheshire
364 Add void LogMsg( const char *format, ... )
366 Revision 1.8 2003/03/22 02:57:44 cheshire
367 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
369 Revision 1.7 2003/03/15 04:40:38 cheshire
370 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
372 Revision 1.6 2003/02/21 01:54:10 cheshire
373 <rdar://problem/3099194> mDNSResponder needs performance improvements
374 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
376 Revision 1.5 2003/02/20 00:59:03 cheshire
377 Brought Windows code up to date so it complies with
378 Josh Graessley's interface changes for IPv6 support.
379 (Actual support for IPv6 on Windows will come later.)
381 Revision 1.4 2002/09/21 20:44:54 zarzycki
384 Revision 1.3 2002/09/20 05:50:45 bradley
385 Multicast DNS platform plugin for Win32
389 - Get unicode name of machine for nice name instead of just the host name.
390 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
391 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
392 - Implement TCP support for truncated packets (only stubs now).
401 #include "CommonServices.h"
402 #include "DebugServices.h"
403 #include "VPCDetect.h"
404 #include "RegNames.h"
407 #include <Iphlpapi.h>
408 #if( !TARGET_OS_WINDOWS_CE )
411 #include <ntsecapi.h>
414 #include "mDNSEmbeddedAPI.h"
416 #include "mDNSWin32.h"
419 #pragma mark == Constants ==
422 //===========================================================================================================================
424 //===========================================================================================================================
426 #define DEBUG_NAME "[mDNSWin32] "
428 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
429 #define MDNS_WINDOWS_ENABLE_IPV4 1
430 #define MDNS_WINDOWS_ENABLE_IPV6 1
431 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
432 #define MDNS_SET_HINFO_STRINGS 0
434 #define kMDNSDefaultName "My Computer"
436 #define kWinSockMajorMin 2
437 #define kWinSockMinorMin 2
439 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
440 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
441 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
442 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
443 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
444 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
445 #define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
447 #define kRegistryMaxKeyLength 255
449 #if( !TARGET_OS_WINDOWS_CE )
450 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
453 #define kIPv6IfIndexBase (10000000L)
457 #pragma mark == Prototypes ==
460 //===========================================================================================================================
462 //===========================================================================================================================
464 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
465 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
466 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
467 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
468 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
469 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
470 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
471 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
472 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
473 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
474 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
475 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
476 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
478 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
479 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
480 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
481 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
482 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
483 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
);
484 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
485 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
* inMDNS
);
486 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
);
487 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
* inMDNS
);
490 // Platform Accessors
496 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
497 struct mDNSPlatformInterfaceInfo
503 typedef struct mDNSTCPConnectionData mDNSTCPConnectionData
;
504 struct mDNSTCPConnectionData
508 TCPConnectionCallback callback
;
511 mDNSTCPConnectionData
* next
;
515 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
516 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
520 typedef struct PolyString PolyString
;
526 PLSA_UNICODE_STRING m_lsa
;
530 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
531 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
534 #if( !TARGET_OS_WINDOWS_CE )
535 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
538 #if( TARGET_OS_WINDOWS_CE )
539 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
542 mDNSlocal DWORD
GetPrimaryInterface();
543 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
544 mDNSlocal mDNSBool
CanReceiveUnicast( void );
545 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
547 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
548 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
549 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
550 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
551 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
552 mDNSlocal OSStatus
MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
);
553 mDNSlocal OSStatus
MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
);
554 mDNSlocal
void FreeTCPConnectionData( mDNSTCPConnectionData
* data
);
561 #pragma mark == Globals ==
564 //===========================================================================================================================
566 //===========================================================================================================================
568 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
569 mDNSs32 mDNSPlatformOneSecond
= 0;
570 mDNSlocal mDNSTCPConnectionData
* gTCPConnectionList
= NULL
;
571 mDNSlocal
int gTCPConnections
= 0;
572 mDNSlocal BOOL gWaitListChanged
= FALSE
;
574 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
577 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
581 PIP_ADAPTER_ADDRESSES inAdapter
,
582 PULONG outBufferSize
);
584 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
585 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
591 #pragma mark == Platform Support ==
594 //===========================================================================================================================
596 //===========================================================================================================================
598 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
603 struct sockaddr_in sa4
;
604 struct sockaddr_in6 sa6
;
608 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
610 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
611 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
613 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
614 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
615 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
616 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
618 // Startup WinSock 2.2 or later.
620 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
621 require_noerr( err
, exit
);
623 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
624 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
626 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
628 // Setup the HINFO HW/SW strings.
630 #if ( MDNS_SET_HINFO_STRINGS )
631 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
633 // Note that GetWindowsVersionString guarantees that the resulting string is always null-terminated,
634 // so the following strlen call is safe
635 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
636 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
638 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
639 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
640 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
641 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
644 // Set up the IPv4 unicast socket
646 inMDNS
->p
->unicastSock4
= INVALID_SOCKET
;
647 inMDNS
->p
->unicastSock4ReadEvent
= NULL
;
648 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
650 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
652 sa4
.sin_family
= AF_INET
;
653 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
654 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
);
656 sa4len
= sizeof( sa4
);
657 err
= getsockname( inMDNS
->p
->unicastSock4
, (struct sockaddr
*) &sa4
, &sa4len
);
658 require_noerr( err
, exit
);
659 inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
660 inMDNS
->p
->unicastSock4ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
661 err
= translate_errno( inMDNS
->p
->unicastSock4ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
662 require_noerr( err
, exit
);
663 err
= WSAEventSelect( inMDNS
->p
->unicastSock4
, inMDNS
->p
->unicastSock4ReadEvent
, FD_READ
);
664 require_noerr( err
, exit
);
665 #if( !TARGET_OS_WINDOWS_CE )
669 // If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
670 // a bug in VPC itself.
672 err
= IsVPCRunning();
676 err
= WSAIoctl( inMDNS
->p
->unicastSock4
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
677 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock4RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock4RecvMsgPtr
), &size
, NULL
, NULL
);
682 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
689 // Set up the IPv6 unicast socket
691 inMDNS
->p
->unicastSock6
= INVALID_SOCKET
;
692 inMDNS
->p
->unicastSock6ReadEvent
= NULL
;
693 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
695 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
697 sa6
.sin6_family
= AF_INET6
;
698 sa6
.sin6_addr
= in6addr_any
;
699 sa6
.sin6_scope_id
= 0;
701 // This call will fail if the machine hasn't installed IPv6. In that case,
702 // the error will be WSAEAFNOSUPPORT.
704 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
);
705 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
706 inMDNS
->p
->unicastSock6ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
707 err
= translate_errno( inMDNS
->p
->unicastSock6ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
708 require_noerr( err
, exit
);
710 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
712 if ( inMDNS
->p
->unicastSock6
!= INVALID_SOCKET
)
714 sa6len
= sizeof( sa6
);
715 err
= getsockname( inMDNS
->p
->unicastSock6
, (struct sockaddr
*) &sa6
, &sa6len
);
716 require_noerr( err
, exit
);
717 inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
719 err
= WSAEventSelect( inMDNS
->p
->unicastSock6
, inMDNS
->p
->unicastSock6ReadEvent
, FD_READ
);
720 require_noerr( err
, exit
);
722 #if( !TARGET_OS_WINDOWS_CE )
726 err
= WSAIoctl( inMDNS
->p
->unicastSock6
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
727 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock6RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock6RecvMsgPtr
), &size
, NULL
, NULL
);
731 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
739 // Set up the mDNS thread.
741 err
= SetupSynchronizationObjects( inMDNS
);
742 require_noerr( err
, exit
);
744 err
= SetupThread( inMDNS
);
745 require_noerr( err
, exit
);
749 mDNSCoreInitComplete( inMDNS
, err
);
754 mDNSPlatformClose( inMDNS
);
756 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
760 //===========================================================================================================================
762 //===========================================================================================================================
764 void mDNSPlatformClose( mDNS
* const inMDNS
)
768 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
771 // Tear everything down in reverse order to how it was set up.
773 err
= TearDownThread( inMDNS
);
776 err
= TearDownInterfaceList( inMDNS
);
778 check( !inMDNS
->p
->inactiveInterfaceList
);
780 err
= TearDownSynchronizationObjects( inMDNS
);
783 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
785 if ( inMDNS
->p
->unicastSock4ReadEvent
)
787 CloseHandle( inMDNS
->p
->unicastSock4ReadEvent
);
788 inMDNS
->p
->unicastSock4ReadEvent
= 0;
791 if ( IsValidSocket( inMDNS
->p
->unicastSock4
) )
793 close_compat( inMDNS
->p
->unicastSock4
);
798 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
800 if ( inMDNS
->p
->unicastSock6ReadEvent
)
802 CloseHandle( inMDNS
->p
->unicastSock6ReadEvent
);
803 inMDNS
->p
->unicastSock6ReadEvent
= 0;
806 if ( IsValidSocket( inMDNS
->p
->unicastSock6
) )
808 close_compat( inMDNS
->p
->unicastSock6
);
813 // Free the DLL needed for IPv6 support.
815 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
816 if( gIPHelperLibraryInstance
)
818 gGetAdaptersAddressesFunctionPtr
= NULL
;
820 FreeLibrary( gIPHelperLibraryInstance
);
821 gIPHelperLibraryInstance
= NULL
;
827 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
830 //===========================================================================================================================
831 // mDNSPlatformSendUDP
832 //===========================================================================================================================
836 const mDNS
* const inMDNS
,
837 const void * const inMsg
,
838 const mDNSu8
* const inMsgEnd
,
839 mDNSInterfaceID inInterfaceID
,
840 const mDNSAddr
* inDstIP
,
841 mDNSIPPort inDstPort
)
843 SOCKET sendingsocket
= INVALID_SOCKET
;
844 mStatus err
= mStatus_NoError
;
845 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
846 struct sockaddr_storage addr
;
849 DEBUG_USE_ONLY( inMDNS
);
851 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
857 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
859 if( inDstIP
->type
== mDNSAddrType_IPv4
)
861 struct sockaddr_in
* sa4
;
863 sa4
= (struct sockaddr_in
*) &addr
;
864 sa4
->sin_family
= AF_INET
;
865 sa4
->sin_port
= inDstPort
.NotAnInteger
;
866 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
867 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock4
;
869 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
871 struct sockaddr_in6
* sa6
;
873 sa6
= (struct sockaddr_in6
*) &addr
;
874 sa6
->sin6_family
= AF_INET6
;
875 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
876 sa6
->sin6_flowinfo
= 0;
877 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
878 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
879 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock6
;
883 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
884 err
= mStatus_BadParamErr
;
888 if (IsValidSocket(sendingsocket
))
890 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
891 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
895 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
897 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
899 err
= mStatus_TransientErr
;
903 require_noerr( err
, exit
);
912 //===========================================================================================================================
914 //===========================================================================================================================
916 void mDNSPlatformLock( const mDNS
* const inMDNS
)
920 if ( inMDNS
->p
->lockInitialized
)
922 EnterCriticalSection( &inMDNS
->p
->lock
);
926 //===========================================================================================================================
927 // mDNSPlatformUnlock
928 //===========================================================================================================================
930 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
935 if ( inMDNS
->p
->lockInitialized
)
937 check( inMDNS
->p
->threadID
);
939 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
940 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
942 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
946 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
947 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
949 LeaveCriticalSection( &inMDNS
->p
->lock
);
953 //===========================================================================================================================
954 // mDNSPlatformStrCopy
955 //===========================================================================================================================
957 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
962 strcpy( (char *) inDst
, (const char*) inSrc
);
965 //===========================================================================================================================
966 // mDNSPlatformStrLen
967 //===========================================================================================================================
969 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
973 return( (mDNSu32
) strlen( (const char *) inSrc
) );
976 //===========================================================================================================================
977 // mDNSPlatformMemCopy
978 //===========================================================================================================================
980 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
985 memcpy( inDst
, inSrc
, inSize
);
988 //===========================================================================================================================
989 // mDNSPlatformMemSame
990 //===========================================================================================================================
992 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
997 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
1000 //===========================================================================================================================
1001 // mDNSPlatformMemZero
1002 //===========================================================================================================================
1004 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
1008 memset( inDst
, 0, inSize
);
1011 //===========================================================================================================================
1012 // mDNSPlatformMemAllocate
1013 //===========================================================================================================================
1015 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
1019 check( inSize
> 0 );
1021 mem
= malloc( inSize
);
1027 //===========================================================================================================================
1028 // mDNSPlatformMemFree
1029 //===========================================================================================================================
1031 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
1038 //===========================================================================================================================
1039 // mDNSPlatformRandomSeed
1040 //===========================================================================================================================
1042 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
1044 return( GetTickCount() );
1047 //===========================================================================================================================
1048 // mDNSPlatformTimeInit
1049 //===========================================================================================================================
1051 mDNSexport mStatus
mDNSPlatformTimeInit( void )
1053 // No special setup is required on Windows -- we just use GetTickCount().
1054 return( mStatus_NoError
);
1057 //===========================================================================================================================
1058 // mDNSPlatformRawTime
1059 //===========================================================================================================================
1061 mDNSs32
mDNSPlatformRawTime( void )
1063 return( (mDNSs32
) GetTickCount() );
1066 //===========================================================================================================================
1068 //===========================================================================================================================
1070 mDNSexport mDNSs32
mDNSPlatformUTC( void )
1072 return ( mDNSs32
) time( NULL
);
1075 //===========================================================================================================================
1076 // mDNSPlatformInterfaceNameToID
1077 //===========================================================================================================================
1079 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
1082 mDNSInterfaceData
* ifd
;
1088 // Search for an interface with the specified name,
1090 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1092 if( strcmp( ifd
->name
, inName
) == 0 )
1097 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1103 *outID
= (mDNSInterfaceID
) ifd
;
1105 err
= mStatus_NoError
;
1111 //===========================================================================================================================
1112 // mDNSPlatformInterfaceIDToInfo
1113 //===========================================================================================================================
1115 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
1118 mDNSInterfaceData
* ifd
;
1124 // Search for an interface with the specified ID,
1126 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1128 if( ifd
== (mDNSInterfaceData
*) inID
)
1133 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1137 outInfo
->name
= ifd
->name
;
1138 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
1139 err
= mStatus_NoError
;
1145 //===========================================================================================================================
1146 // mDNSPlatformInterfaceIDfromInterfaceIndex
1147 //===========================================================================================================================
1149 mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS
* const inMDNS
, mDNSu32 inIndex
)
1154 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
1156 id
= mDNSInterface_LocalOnly
;
1158 else if( inIndex
!= 0 )
1160 mDNSInterfaceData
* ifd
;
1162 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1164 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
1166 id
= ifd
->interfaceInfo
.InterfaceID
;
1175 //===========================================================================================================================
1176 // mDNSPlatformInterfaceIndexfromInterfaceID
1177 //===========================================================================================================================
1179 mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS
* const inMDNS
, mDNSInterfaceID inID
)
1184 if( inID
== mDNSInterface_LocalOnly
)
1186 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
1190 mDNSInterfaceData
* ifd
;
1192 // Search active interfaces.
1193 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1195 if( (mDNSInterfaceID
) ifd
== inID
)
1197 index
= ifd
->scopeID
;
1202 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
1206 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
1208 if( (mDNSInterfaceID
) ifd
== inID
)
1210 index
= ifd
->scopeID
;
1220 //===========================================================================================================================
1221 // mDNSPlatformTCPConnect
1222 //===========================================================================================================================
1225 mDNSPlatformTCPConnect(
1226 const mDNSAddr
* inDstIP
,
1227 mDNSOpaque16 inDstPort
,
1228 mDNSInterfaceID inInterfaceID
,
1229 TCPConnectionCallback inCallback
,
1233 u_long on
= 1; // "on" for setsockopt
1234 struct sockaddr_in saddr
;
1235 mDNSTCPConnectionData
* tcd
= NULL
;
1236 mStatus err
= mStatus_NoError
;
1238 DEBUG_UNUSED( inInterfaceID
);
1240 *outSock
= INVALID_SOCKET
;
1242 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1244 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1245 return mStatus_UnknownErr
;
1248 // Setup connection data object
1250 tcd
= (mDNSTCPConnectionData
*) malloc( sizeof( mDNSTCPConnectionData
) );
1251 require_action( tcd
, exit
, err
= mStatus_NoMemoryErr
);
1252 memset( tcd
, 0, sizeof( mDNSTCPConnectionData
) );
1254 tcd
->sock
= INVALID_SOCKET
;
1255 tcd
->callback
= inCallback
;
1256 tcd
->context
= inContext
;
1258 bzero(&saddr
, sizeof(saddr
));
1259 saddr
.sin_family
= AF_INET
;
1260 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1261 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1263 // Create the socket
1265 tcd
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
1266 err
= translate_errno( tcd
->sock
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
1267 require_noerr( err
, exit
);
1269 // Set it to be non-blocking
1271 err
= ioctlsocket( tcd
->sock
, FIONBIO
, &on
);
1272 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1273 require_noerr( err
, exit
);
1275 // Try and do connect
1277 err
= connect( tcd
->sock
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1278 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1279 tcd
->connected
= !err
? TRUE
: FALSE
;
1280 tcd
->pendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1281 err
= translate_errno( tcd
->pendingEvent
, GetLastError(), mStatus_UnknownErr
);
1282 require_noerr( err
, exit
);
1283 err
= WSAEventSelect( tcd
->sock
, tcd
->pendingEvent
, FD_CONNECT
|FD_READ
|FD_CLOSE
);
1284 require_noerr( err
, exit
);
1288 tcd
->next
= gTCPConnectionList
;
1289 gTCPConnectionList
= tcd
;
1291 gWaitListChanged
= TRUE
;
1293 *outSock
= (int) tcd
->sock
;
1299 err
= tcd
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1303 FreeTCPConnectionData( tcd
);
1309 //===========================================================================================================================
1310 // mDNSPlatformTCPCloseConnection
1311 //===========================================================================================================================
1313 void mDNSPlatformTCPCloseConnection( int inSock
)
1315 mDNSTCPConnectionData
* tcd
= gTCPConnectionList
;
1316 mDNSTCPConnectionData
* last
= NULL
;
1320 if ( tcd
->sock
== ( SOCKET
) inSock
)
1324 gTCPConnectionList
= tcd
->next
;
1328 last
->next
= tcd
->next
;
1331 FreeTCPConnectionData( tcd
);
1334 gWaitListChanged
= TRUE
;
1344 //===========================================================================================================================
1345 // mDNSPlatformReadTCP
1346 //===========================================================================================================================
1348 int mDNSPlatformReadTCP( int inSock
, void *inBuffer
, int inBufferSize
)
1353 nread
= recv( inSock
, inBuffer
, inBufferSize
, 0);
1354 err
= translate_errno( ( nread
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1355 require_noerr( err
, exit
);
1367 //===========================================================================================================================
1368 // mDNSPlatformWriteTCP
1369 //===========================================================================================================================
1371 int mDNSPlatformWriteTCP( int inSock
, const char *inMsg
, int inMsgSize
)
1376 nsent
= send( inSock
, inMsg
, inMsgSize
, 0 );
1378 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1379 require_noerr( err
, exit
);
1391 //===========================================================================================================================
1392 // dDNSPlatformGetConfig
1393 //===========================================================================================================================
1396 dDNSPlatformGetConfig(domainname
* const fqdn
, domainname
*const regDomain
, DNameListElem
** browseDomains
)
1399 char subKeyName
[kRegistryMaxKeyLength
+ 1];
1413 fqdn
->c
[0] = regDomain
->c
[0] = '\0';
1415 *browseDomains
= NULL
;
1417 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
1418 require_noerr( err
, exit
);
1420 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1421 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1423 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
1425 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
1441 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
, &key
);
1442 require_noerr( err
, exit
);
1444 // Get information about this node
1446 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
1447 require_noerr( err
, exit
);
1449 for ( i
= 0; i
< cSubKeys
; i
++)
1453 dwSize
= kRegistryMaxKeyLength
;
1455 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1459 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
1460 require_noerr( err
, exit
);
1462 dwSize
= sizeof( DWORD
);
1463 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
1465 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
1467 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
1469 dlog( kDebugLevelError
, "bad DDNS browse domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
1473 DNameListElem
* browseDomain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1474 require_action( browseDomain
, exit
, err
= mStatus_NoMemoryErr
);
1476 AssignDomainName(&browseDomain
->name
, &dname
);
1477 browseDomain
->next
= *browseDomains
;
1479 *browseDomains
= browseDomain
;
1483 RegCloseKey( subKey
);
1494 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
, &key
);
1495 require_noerr( err
, exit
);
1497 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1498 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1500 if ( !MakeDomainNameFromDNSNameString( regDomain
, name
) || !regDomain
->c
[0] )
1502 dlog( kDebugLevelError
, "bad DDNS registration domain in registry: %s", name
[0] ? name
: "(unknown)");
1510 RegCloseKey( subKey
);
1525 //===========================================================================================================================
1526 // dDNSPlatformSetNameStatus
1527 //===========================================================================================================================
1530 dDNSPlatformSetNameStatus(domainname
*const dname
, mStatus status
)
1532 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1538 ConvertDomainNameToCString(dname
, uname
);
1544 *p
= (char) tolower(*p
);
1545 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1549 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1550 name
= kServiceParametersNode
TEXT("\\DynDNS\\State\\HostNames");
1551 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1552 require_noerr( err
, exit
);
1554 status
= ( status
) ? 0 : 1;
1555 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &status
, sizeof(DWORD
) );
1556 require_noerr( err
, exit
);
1569 //===========================================================================================================================
1570 // dDNSPlatformSetSecretForDomain
1571 //===========================================================================================================================
1574 dDNSPlatformSetSecretForDomain( mDNS
*m
, const domainname
* inDomain
)
1581 LSA_OBJECT_ATTRIBUTES attrs
;
1582 LSA_HANDLE handle
= NULL
;
1586 // Initialize PolyStrings
1588 domain
.m_lsa
= NULL
;
1590 secret
.m_lsa
= NULL
;
1592 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
1594 ConvertDomainNameToCString( inDomain
, domain
.m_utf8
);
1595 dlen
= strlen( domain
.m_utf8
);
1596 for ( i
= 0; i
< dlen
; i
++ )
1598 domain
.m_utf8
[i
] = (char) tolower( domain
.m_utf8
[i
] ); // canonicalize -> lower case
1601 MakeDomainNameFromDNSNameString( &domain
.m_dname
, domain
.m_utf8
);
1603 // attrs are reserved, so initialize to zeroes.
1605 ZeroMemory( &attrs
, sizeof( attrs
) );
1607 // Get a handle to the Policy object on the local system
1609 res
= LsaOpenPolicy( NULL
, &attrs
, POLICY_GET_PRIVATE_INFORMATION
, &handle
);
1610 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1611 require_noerr( err
, exit
);
1613 // Get the encrypted data
1615 domain
.m_lsa
= ( PLSA_UNICODE_STRING
) malloc( sizeof( LSA_UNICODE_STRING
) );
1616 require_action( domain
.m_lsa
!= NULL
, exit
, err
= mStatus_NoMemoryErr
);
1617 err
= MakeLsaStringFromUTF8String( domain
.m_lsa
, domain
.m_utf8
);
1618 require_noerr( err
, exit
);
1622 res
= LsaRetrievePrivateData( handle
, domain
.m_lsa
, &key
.m_lsa
);
1623 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1624 require_noerr_quiet( err
, exit
);
1626 // <rdar://problem/4192119> Lsa secrets use a flat naming space. Therefore, we will prepend "$" to the keyname to
1627 // make sure it doesn't conflict with a zone name.
1629 // Convert the key to a domainname. Strip off the "$" prefix.
1631 err
= MakeUTF8StringFromLsaString( key
.m_utf8
, sizeof( key
.m_utf8
), key
.m_lsa
);
1632 require_noerr( err
, exit
);
1633 require_action( key
.m_utf8
[0] == '$', exit
, err
= kUnknownErr
);
1634 MakeDomainNameFromDNSNameString( &key
.m_dname
, key
.m_utf8
+ 1 );
1636 // Retrieve the secret
1638 res
= LsaRetrievePrivateData( handle
, key
.m_lsa
, &secret
.m_lsa
);
1639 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1640 require_noerr_quiet( err
, exit
);
1642 // Convert the secret to UTF8 string
1644 err
= MakeUTF8StringFromLsaString( secret
.m_utf8
, sizeof( secret
.m_utf8
), secret
.m_lsa
);
1645 require_noerr( err
, exit
);
1647 // And finally, tell the core about this secret
1649 debugf("Setting shared secret for zone %s with key %##s", domain
.m_utf8
, key
.m_dname
.c
);
1650 mDNS_SetSecretForZone( m
, &domain
.m_dname
, &key
.m_dname
, secret
.m_utf8
);
1654 if ( domain
.m_lsa
!= NULL
)
1656 if ( domain
.m_lsa
->Buffer
!= NULL
)
1658 free( domain
.m_lsa
->Buffer
);
1661 free( domain
.m_lsa
);
1664 if ( key
.m_lsa
!= NULL
)
1666 LsaFreeMemory( key
.m_lsa
);
1669 if ( secret
.m_lsa
!= NULL
)
1671 LsaFreeMemory( secret
.m_lsa
);
1682 //===========================================================================================================================
1683 // dDNSPlatformGetSearchDomainList
1684 //===========================================================================================================================
1687 dDNSPlatformGetSearchDomainList( void )
1689 char * searchList
= NULL
;
1690 DWORD searchListLen
;
1691 DNameListElem
* head
= NULL
;
1692 DNameListElem
* current
= NULL
;
1697 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1698 require_noerr( err
, exit
);
1700 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1701 require_noerr( err
, exit
);
1703 // Windows separates the search domains with ','
1705 tok
= strtok( searchList
, "," );
1708 if ( ( strcmp( tok
, "" ) != 0 ) && ( strcmp( tok
, "." ) != 0 ) )
1712 if ( MakeDomainNameFromDNSNameString( &domain
, tok
) )
1714 DNameListElem
* last
= current
;
1716 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1717 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1719 AssignDomainName( ¤t
->name
, &domain
);
1720 current
->next
= NULL
;
1729 last
->next
= current
;
1734 tok
= strtok( NULL
, "," );
1753 //===========================================================================================================================
1754 // dDNSPlatformGetReverseMapSearchDomainList
1755 //===========================================================================================================================
1758 dDNSPlatformGetReverseMapSearchDomainList( void )
1760 DNameListElem
* head
= NULL
;
1761 DNameListElem
* current
= NULL
;
1762 struct ifaddrs
* ifa
;
1765 ifa
= myGetIfAddrs( 1 );
1770 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !dDNS_SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1776 if (!dDNS_SetupAddr(&netmask
, ifa
->ifa_netmask
))
1778 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1779 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1780 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1781 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1783 if ( MakeDomainNameFromDNSNameString( &domain
, buffer
) )
1785 DNameListElem
* last
= current
;
1787 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1788 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1790 AssignDomainName( ¤t
->name
, &domain
);
1791 current
->next
= NULL
;
1800 last
->next
= current
;
1806 ifa
= ifa
->ifa_next
;
1815 //===========================================================================================================================
1816 // dDNSPlatformGetDNSServers
1817 //===========================================================================================================================
1820 dDNSPlatformGetDNSServers( void )
1822 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1823 FIXED_INFO
* fixedInfo
= NULL
;
1825 IP_ADDR_STRING
* dnsServerList
;
1826 IP_ADDR_STRING
* ipAddr
;
1827 IPAddrListElem
* head
= NULL
;
1828 IPAddrListElem
* current
= NULL
;
1831 mStatus err
= kUnknownErr
;
1833 // Get the primary interface.
1835 index
= GetPrimaryInterface();
1837 // This should have the interface index of the primary index. Fall back in cases where
1838 // it can't be determined.
1844 for ( i
= 0; i
< 100; i
++ )
1846 err
= GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
);
1848 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1853 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1854 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1857 require_noerr( err
, exit
);
1859 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1863 bufLen
= sizeof( FIXED_INFO
);
1865 for ( i
= 0; i
< 100; i
++ )
1869 GlobalFree( fixedInfo
);
1873 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1874 require_action( fixedInfo
, exit
, err
= mStatus_NoMemoryErr
);
1876 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1878 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1884 require_noerr( err
, exit
);
1886 dnsServerList
= &fixedInfo
->DnsServerList
;
1889 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1892 IPAddrListElem
* last
= current
;
1894 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1901 current
= (IPAddrListElem
*) malloc( sizeof( IPAddrListElem
) );
1902 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1904 memcpy( ¤t
->addr
, &addr
, sizeof( mDNSAddr
) );
1905 current
->next
= NULL
;
1914 last
->next
= current
;
1922 free( pAdapterInfo
);
1927 GlobalFree( fixedInfo
);
1934 //===========================================================================================================================
1935 // dDNSPlatformGetDomainName
1936 //===========================================================================================================================
1939 dDNSPlatformGetDomainName( void )
1941 DNameListElem
* head
= NULL
;
1943 IP_ADAPTER_INFO
* pAdapterInfo
;
1944 IP_ADAPTER_INFO
* pAdapter
;
1948 LPSTR domain
= NULL
;
1951 mStatus err
= mStatus_NoError
;
1953 pAdapterInfo
= NULL
;
1955 for ( i
= 0; i
< 100; i
++ )
1957 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1959 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1964 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
1965 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1968 require_noerr( err
, exit
);
1970 index
= GetPrimaryInterface();
1972 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1974 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1975 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1976 pAdapter
->GatewayList
.IpAddress
.String
&&
1977 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1978 ( !index
|| ( pAdapter
->Index
== index
) ) )
1980 // Found one that will work
1984 _snprintf( keyName
, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter
->AdapterName
);
1986 err
= RegCreateKeyA( HKEY_LOCAL_MACHINE
, keyName
, &key
);
1987 require_noerr( err
, exit
);
1989 err
= RegQueryString( key
, "Domain", &domain
, &dwSize
, NULL
);
1992 if ( !domain
|| !domain
[0] )
2000 err
= RegQueryString( key
, "DhcpDomain", &domain
, &dwSize
, NULL
);
2004 if ( domain
&& domain
[0] && ( MakeDomainNameFromDNSNameString( &dname
, domain
) || !dname
.c
[0] ) )
2006 head
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
2007 require_action( head
, exit
, err
= mStatus_NoMemoryErr
);
2009 AssignDomainName( &head
->name
, &dname
);
2021 free( pAdapterInfo
);
2038 //===========================================================================================================================
2039 // dDNSPlatformRegisterSplitDNS
2040 //===========================================================================================================================
2043 dDNSPlatformRegisterSplitDNS( mDNS
* m
)
2047 return mStatus_UnsupportedErr
;
2051 //===========================================================================================================================
2052 // dDNSPlatformGetPrimaryInterface
2053 //===========================================================================================================================
2056 dDNSPlatformGetPrimaryInterface( mDNS
* m
, mDNSAddr
* primary
, mDNSAddr
* router
)
2058 IP_ADAPTER_INFO
* pAdapterInfo
;
2059 IP_ADAPTER_INFO
* pAdapter
;
2064 mStatus err
= mStatus_NoError
;
2068 pAdapterInfo
= NULL
;
2072 for ( i
= 0; i
< 100; i
++ )
2074 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2076 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2081 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2082 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2085 require_noerr( err
, exit
);
2087 index
= GetPrimaryInterface();
2089 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2091 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2092 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2093 pAdapter
->GatewayList
.IpAddress
.String
&&
2094 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2095 ( StringToAddress( primary
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
2096 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
2097 ( !index
|| ( pAdapter
->Index
== index
) ) )
2099 // Found one that will work
2110 free( pAdapterInfo
);
2117 //===========================================================================================================================
2118 // dDNSPlatformDefaultBrowseDomainChanged
2119 //===========================================================================================================================
2122 dDNSPlatformDefaultBrowseDomainChanged( const domainname
*d
, mDNSBool add
)
2125 DEBUG_UNUSED( add
);
2127 // This is a no-op on Windows
2131 //===========================================================================================================================
2132 // dDNSPlatformDefaultRegDomainChanged
2133 //===========================================================================================================================
2136 dDNSPlatformDefaultRegDomainChanged( const domainname
* d
, mDNSBool add
)
2139 DEBUG_UNUSED( add
);
2141 // This is a no-op on Windows
2149 //===========================================================================================================================
2151 //===========================================================================================================================
2153 #if( MDNS_DEBUGMSGS )
2154 void debugf_( const char *inFormat
, ... )
2160 va_start( args
, inFormat
);
2161 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2164 dlog( kDebugLevelInfo
, "%s\n", buffer
);
2168 //===========================================================================================================================
2170 //===========================================================================================================================
2172 #if( MDNS_DEBUGMSGS > 1 )
2173 void verbosedebugf_( const char *inFormat
, ... )
2179 va_start( args
, inFormat
);
2180 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2183 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
2187 //===========================================================================================================================
2189 //===========================================================================================================================
2192 void LogMsg( const char *inFormat, ... )
2198 va_start( args, inFormat );
2199 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2202 dlog( kDebugLevelWarning, "%s\n", buffer );
2208 #pragma mark == Platform Internals ==
2211 //===========================================================================================================================
2212 // SetupSynchronizationObjects
2213 //===========================================================================================================================
2215 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
2219 InitializeCriticalSection( &inMDNS
->p
->lock
);
2220 inMDNS
->p
->lockInitialized
= mDNStrue
;
2222 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2223 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2224 require_noerr( err
, exit
);
2226 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2227 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2228 require_noerr( err
, exit
);
2230 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2231 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2232 require_noerr( err
, exit
);
2234 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2235 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2236 require_noerr( err
, exit
);
2241 TearDownSynchronizationObjects( inMDNS
);
2246 //===========================================================================================================================
2247 // TearDownSynchronizationObjects
2248 //===========================================================================================================================
2250 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
2252 if( inMDNS
->p
->quitEvent
)
2254 CloseHandle( inMDNS
->p
->quitEvent
);
2255 inMDNS
->p
->quitEvent
= 0;
2257 if( inMDNS
->p
->cancelEvent
)
2259 CloseHandle( inMDNS
->p
->cancelEvent
);
2260 inMDNS
->p
->cancelEvent
= 0;
2262 if( inMDNS
->p
->interfaceListChangedEvent
)
2264 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
2265 inMDNS
->p
->interfaceListChangedEvent
= 0;
2267 if( inMDNS
->p
->wakeupEvent
)
2269 CloseHandle( inMDNS
->p
->wakeupEvent
);
2270 inMDNS
->p
->wakeupEvent
= 0;
2272 if( inMDNS
->p
->lockInitialized
)
2274 DeleteCriticalSection( &inMDNS
->p
->lock
);
2275 inMDNS
->p
->lockInitialized
= mDNSfalse
;
2277 return( mStatus_NoError
);
2281 //===========================================================================================================================
2283 //===========================================================================================================================
2285 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
)
2288 char tempString
[ 256 ];
2293 // Set up the nice name.
2294 tempString
[ 0 ] = '\0';
2297 // First try and open the registry key that contains the computer description value
2298 if (inMDNS
->p
->descKey
== NULL
)
2300 LPCTSTR s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2301 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &inMDNS
->p
->descKey
);
2302 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2306 inMDNS
->p
->descKey
= NULL
;
2310 // if we opened it...
2311 if (inMDNS
->p
->descKey
!= NULL
)
2314 DWORD descSize
= sizeof( desc
);
2316 // look for the computer description
2317 err
= RegQueryValueEx(inMDNS
->p
->descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2321 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2330 // if we can't find it in the registry, then use the hostname of the machine
2331 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2333 DWORD tempStringLen
= sizeof( tempString
);
2336 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2337 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2342 err
= WindowsLatin1toUTF8( tempString
, utf8
, sizeof( utf8
) );
2351 // if we can't get the hostname
2352 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2354 // Invalidate name so fall back to a default name.
2356 strcpy( utf8
, kMDNSDefaultName
);
2359 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2360 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2361 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2363 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2369 //===========================================================================================================================
2371 //===========================================================================================================================
2373 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2376 char tempString
[ 256 ];
2377 DWORD tempStringLen
;
2378 domainlabel tempLabel
;
2383 // Set up the nice name.
2384 tempString
[ 0 ] = '\0';
2386 // use the hostname of the machine
2387 tempStringLen
= sizeof( tempString
);
2388 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2389 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2392 // if we can't get the hostname
2393 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2395 // Invalidate name so fall back to a default name.
2397 strcpy( tempString
, kMDNSDefaultName
);
2400 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2401 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2402 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2404 // Set up the host name.
2406 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2407 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2409 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2411 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2414 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2416 mDNS_SetFQDN( inMDNS
);
2418 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2423 //===========================================================================================================================
2425 //===========================================================================================================================
2427 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2433 err
= SetupNiceName( inMDNS
);
2436 err
= SetupHostName( inMDNS
);
2443 //===========================================================================================================================
2444 // SetupInterfaceList
2445 //===========================================================================================================================
2447 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2450 mDNSInterfaceData
** next
;
2451 mDNSInterfaceData
* ifd
;
2452 struct ifaddrs
* addrs
;
2454 struct ifaddrs
* loopbackv4
;
2455 struct ifaddrs
* loopbackv6
;
2460 mDNSBool foundUnicastSock4DestAddr
;
2461 mDNSBool foundUnicastSock6DestAddr
;
2463 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2467 inMDNS
->p
->registeredLoopback4
= mDNSfalse
;
2469 foundv4
= mDNSfalse
;
2470 foundv6
= mDNSfalse
;
2471 foundUnicastSock4DestAddr
= mDNSfalse
;
2472 foundUnicastSock6DestAddr
= mDNSfalse
;
2474 // Tear down any existing interfaces that may be set up.
2476 TearDownInterfaceList( inMDNS
);
2478 // Set up the name of this machine.
2480 err
= SetupName( inMDNS
);
2483 // Set up the interface list change notification.
2485 err
= SetupNotifications( inMDNS
);
2488 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2489 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2491 err
= getifaddrs( &addrs
);
2492 require_noerr( err
, exit
);
2496 next
= &inMDNS
->p
->interfaceList
;
2498 flagMask
= IFF_UP
| IFF_MULTICAST
;
2499 flagTest
= IFF_UP
| IFF_MULTICAST
;
2501 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2502 for( p
= addrs
; p
; p
= p
->ifa_next
)
2504 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2508 if( p
->ifa_flags
& IFF_LOOPBACK
)
2516 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2517 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2519 err
= SetupInterface( inMDNS
, p
, &ifd
);
2520 require_noerr( err
, exit
);
2522 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2523 // register him, but we also want to note that we haven't found a v4 interface
2524 // so that we register loopback so same host operations work
2526 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2531 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2532 // of determing the destination address of a packet that is sent to us.
2533 // For multicast packets, that's easy to determine. But for the unicast
2534 // sockets, we'll fake it by taking the address of the first interface
2535 // that is successfully setup.
2537 if ( !foundUnicastSock4DestAddr
)
2539 inMDNS
->p
->unicastSock4DestAddr
= ifd
->interfaceInfo
.ip
;
2540 foundUnicastSock4DestAddr
= TRUE
;
2545 ++inMDNS
->p
->interfaceCount
;
2549 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2551 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2552 for( p
= addrs
; p
; p
= p
->ifa_next
)
2554 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2558 if( p
->ifa_flags
& IFF_LOOPBACK
)
2566 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2567 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2569 err
= SetupInterface( inMDNS
, p
, &ifd
);
2570 require_noerr( err
, exit
);
2572 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2573 // register him, but we also want to note that we haven't found a v4 interface
2574 // so that we register loopback so same host operations work
2576 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2581 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2582 // of determing the destination address of a packet that is sent to us.
2583 // For multicast packets, that's easy to determine. But for the unicast
2584 // sockets, we'll fake it by taking the address of the first interface
2585 // that is successfully setup.
2587 if ( !foundUnicastSock6DestAddr
)
2589 inMDNS
->p
->unicastSock6DestAddr
= ifd
->interfaceInfo
.ip
;
2590 foundUnicastSock6DestAddr
= TRUE
;
2595 ++inMDNS
->p
->interfaceCount
;
2599 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2601 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2603 flagMask
|= IFF_LOOPBACK
;
2604 flagTest
|= IFF_LOOPBACK
;
2606 for( p
= addrs
; p
; p
= p
->ifa_next
)
2608 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2612 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2623 if ( !foundv4
&& loopbackv4
)
2625 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2626 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2628 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2629 require_noerr( err
, exit
);
2631 inMDNS
->p
->registeredLoopback4
= mDNStrue
;
2633 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2635 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2636 // of determing the destination address of a packet that is sent to us.
2637 // For multicast packets, that's easy to determine. But for the unicast
2638 // sockets, we'll fake it by taking the address of the first interface
2639 // that is successfully setup.
2641 if ( !foundUnicastSock4DestAddr
)
2643 inMDNS
->p
->unicastSock4DestAddr
= ifd
->defaultAddr
;
2644 foundUnicastSock4DestAddr
= TRUE
;
2650 ++inMDNS
->p
->interfaceCount
;
2656 TearDownInterfaceList( inMDNS
);
2660 freeifaddrs( addrs
);
2662 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2666 //===========================================================================================================================
2667 // TearDownInterfaceList
2668 //===========================================================================================================================
2670 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2673 mDNSInterfaceData
** p
;
2674 mDNSInterfaceData
* ifd
;
2676 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2680 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2681 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2682 // so that remove events that occur after an interface goes away can still report the correct interface.
2684 p
= &inMDNS
->p
->inactiveInterfaceList
;
2688 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2694 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2699 // Tear down interface list change notifications.
2701 err
= TearDownNotifications( inMDNS
);
2704 // Tear down all the interfaces.
2706 while( inMDNS
->p
->interfaceList
)
2708 ifd
= inMDNS
->p
->interfaceList
;
2709 inMDNS
->p
->interfaceList
= ifd
->next
;
2711 TearDownInterface( inMDNS
, ifd
);
2713 inMDNS
->p
->interfaceCount
= 0;
2715 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2716 return( mStatus_NoError
);
2719 //===========================================================================================================================
2721 //===========================================================================================================================
2723 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2725 mDNSInterfaceData
* ifd
;
2726 mDNSInterfaceData
* p
;
2731 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2735 check( inIFA
->ifa_addr
);
2738 // Allocate memory for the interface and initialize it.
2740 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2741 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2742 ifd
->sock
= kInvalidSocketRef
;
2743 ifd
->index
= inIFA
->ifa_extra
.index
;
2744 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2745 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2746 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2747 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2749 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2750 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2752 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2753 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2754 // on a large configured network, which means there's a good chance that most or all the other devices on that
2755 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2756 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2757 // devices on a large configured network, so we are willing to make that sacrifice.
2759 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2760 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2762 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2764 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2766 if (!ifd
->interfaceInfo
.InterfaceID
)
2768 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2771 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2772 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2773 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2775 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2782 if ( !ifd
->interfaceInfo
.InterfaceID
)
2784 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2787 // Set up a socket for this interface (if needed).
2789 if( ifd
->interfaceInfo
.McastTxRx
)
2791 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &sock
);
2792 require_noerr( err
, exit
);
2794 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2796 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2798 #if( !TARGET_OS_WINDOWS_CE )
2802 // If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
2803 // a bug in VPC itself.
2805 err
= IsVPCRunning();
2809 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
2810 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
2815 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
2820 // Set up the read pending event and associate it so we can block until data is available for this socket.
2822 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2823 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2824 require_noerr( err
, exit
);
2826 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
2827 require_noerr( err
, exit
);
2831 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2833 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2834 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2835 require_noerr( err
, exit
);
2838 // Register this interface with mDNS.
2840 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2841 require_noerr( err
, exit
);
2843 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2844 require_noerr( err
, exit
);
2846 ifd
->interfaceInfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
2848 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, 0 );
2849 require_noerr( err
, exit
);
2850 ifd
->hostRegistered
= mDNStrue
;
2852 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2862 TearDownInterface( inMDNS
, ifd
);
2864 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2868 //===========================================================================================================================
2869 // TearDownInterface
2870 //===========================================================================================================================
2872 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2879 // Deregister this interface with mDNS.
2881 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2883 if( inIFD
->hostRegistered
)
2885 inIFD
->hostRegistered
= mDNSfalse
;
2886 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
);
2889 // Tear down the multicast socket.
2891 if( inIFD
->readPendingEvent
)
2893 CloseHandle( inIFD
->readPendingEvent
);
2894 inIFD
->readPendingEvent
= 0;
2898 inIFD
->sock
= kInvalidSocketRef
;
2899 if( IsValidSocket( sock
) )
2901 close_compat( sock
);
2904 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2905 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2907 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2909 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2910 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2911 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2915 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2918 return( mStatus_NoError
);
2921 //===========================================================================================================================
2923 //===========================================================================================================================
2925 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2931 DEBUG_UNUSED( inMDNS
);
2933 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2935 check( outSocketRef
);
2937 // Set up an IPv4 or IPv6 UDP socket.
2939 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2940 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2941 require_noerr( err
, exit
);
2943 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2944 // if we're creating a multicast socket
2946 if ( port
.NotAnInteger
)
2949 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2950 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2953 if( inAddr
->sa_family
== AF_INET
)
2956 struct sockaddr_in sa4
;
2957 struct ip_mreq mreqv4
;
2959 // Bind the socket to the desired port
2961 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2962 memset( &sa4
, 0, sizeof( sa4
) );
2963 sa4
.sin_family
= AF_INET
;
2964 sa4
.sin_port
= port
.NotAnInteger
;
2965 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2967 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2968 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2970 // Turn on option to receive destination addresses and receiving interface.
2973 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2974 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2976 if (port
.NotAnInteger
)
2978 // Join the all-DNS multicast group so we receive Multicast DNS packets
2980 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
2981 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
2982 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
2983 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2985 // Specify the interface to send multicast packets on this socket.
2987 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2988 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
2989 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2991 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2994 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2995 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2998 // Send unicast packets with TTL 255 (helps against spoofing).
3001 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
3002 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3004 // Send multicast packets with TTL 255 (helps against spoofing).
3007 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
3008 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3011 else if( inAddr
->sa_family
== AF_INET6
)
3013 struct sockaddr_in6
* sa6p
;
3014 struct sockaddr_in6 sa6
;
3015 struct ipv6_mreq mreqv6
;
3017 sa6p
= (struct sockaddr_in6
*) inAddr
;
3019 // Bind the socket to the desired port
3021 memset( &sa6
, 0, sizeof( sa6
) );
3022 sa6
.sin6_family
= AF_INET6
;
3023 sa6
.sin6_port
= port
.NotAnInteger
;
3024 sa6
.sin6_flowinfo
= 0;
3025 sa6
.sin6_addr
= sa6p
->sin6_addr
;
3026 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
3028 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
3029 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
3031 // Turn on option to receive destination addresses and receiving interface.
3034 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
3035 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3037 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
3038 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
3039 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
3041 #if( defined( IPV6_V6ONLY ) )
3043 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
3044 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3047 if ( port
.NotAnInteger
)
3049 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3051 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroupv6
);
3052 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
3053 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
3054 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3056 // Specify the interface to send multicast packets on this socket.
3058 option
= (int) sa6p
->sin6_scope_id
;
3059 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
3060 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3062 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3065 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3066 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3069 // Send unicast packets with TTL 255 (helps against spoofing).
3072 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
3073 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3075 // Send multicast packets with TTL 255 (helps against spoofing).
3078 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
3079 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3083 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
3084 err
= kUnsupportedErr
;
3090 *outSocketRef
= sock
;
3091 sock
= kInvalidSocketRef
;
3092 err
= mStatus_NoError
;
3095 if( IsValidSocket( sock
) )
3097 close_compat( sock
);
3102 //===========================================================================================================================
3104 //===========================================================================================================================
3106 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
3113 if( inSA
->sa_family
== AF_INET
)
3115 struct sockaddr_in
* sa4
;
3117 sa4
= (struct sockaddr_in
*) inSA
;
3118 outIP
->type
= mDNSAddrType_IPv4
;
3119 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
3122 outPort
->NotAnInteger
= sa4
->sin_port
;
3124 err
= mStatus_NoError
;
3126 else if( inSA
->sa_family
== AF_INET6
)
3128 struct sockaddr_in6
* sa6
;
3130 sa6
= (struct sockaddr_in6
*) inSA
;
3131 outIP
->type
= mDNSAddrType_IPv6
;
3132 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
3133 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
3135 outIP
->ip
.v6
.w
[ 1 ] = 0;
3139 outPort
->NotAnInteger
= sa6
->sin6_port
;
3141 err
= mStatus_NoError
;
3145 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
3146 err
= mStatus_BadParamErr
;
3151 //===========================================================================================================================
3152 // SetupNotifications
3153 //===========================================================================================================================
3155 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
3159 unsigned long param
;
3164 // Register to listen for address list changes.
3166 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3167 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
3168 require_noerr( err
, exit
);
3169 inMDNS
->p
->interfaceListChangedSocket
= sock
;
3171 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
3172 // when a change to the interface list is detected.
3175 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
3176 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3177 require_noerr( err
, exit
);
3181 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
3184 check( errno_compat() == WSAEWOULDBLOCK
);
3187 err
= WSAEventSelect( sock
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
3188 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3189 require_noerr( err
, exit
);
3191 inMDNS
->p
->descChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
3192 err
= translate_errno( inMDNS
->p
->descChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3193 require_noerr( err
, exit
);
3195 if (inMDNS
->p
->descKey
!= NULL
)
3197 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3198 require_noerr( err
, exit
);
3201 // This will catch all changes to tcp/ip networking, including changes to the domain search list
3203 inMDNS
->p
->tcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3204 err
= translate_errno( inMDNS
->p
->tcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3205 require_noerr( err
, exit
);
3207 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS
->p
->tcpipKey
);
3208 require_noerr( err
, exit
);
3210 err
= RegNotifyChangeKeyValue(inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3211 require_noerr( err
, exit
);
3213 // This will catch all changes to ddns configuration
3215 inMDNS
->p
->ddnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3216 err
= translate_errno( inMDNS
->p
->ddnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3217 require_noerr( err
, exit
);
3219 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &inMDNS
->p
->ddnsKey
);
3220 require_noerr( err
, exit
);
3222 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3223 require_noerr( err
, exit
);
3228 TearDownNotifications( inMDNS
);
3233 //===========================================================================================================================
3234 // TearDownNotifications
3235 //===========================================================================================================================
3237 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
3239 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
3241 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
3242 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
3245 if ( inMDNS
->p
->descChangedEvent
!= NULL
)
3247 CloseHandle( inMDNS
->p
->descChangedEvent
);
3248 inMDNS
->p
->descChangedEvent
= NULL
;
3251 if ( inMDNS
->p
->descKey
!= NULL
)
3253 RegCloseKey( inMDNS
->p
->descKey
);
3254 inMDNS
->p
->descKey
= NULL
;
3257 if ( inMDNS
->p
->tcpipChangedEvent
!= NULL
)
3259 CloseHandle( inMDNS
->p
->tcpipChangedEvent
);
3260 inMDNS
->p
->tcpipChangedEvent
= NULL
;
3263 if ( inMDNS
->p
->ddnsChangedEvent
!= NULL
)
3265 CloseHandle( inMDNS
->p
->ddnsChangedEvent
);
3266 inMDNS
->p
->ddnsChangedEvent
= NULL
;
3269 if ( inMDNS
->p
->ddnsKey
!= NULL
)
3271 RegCloseKey( inMDNS
->p
->ddnsKey
);
3272 inMDNS
->p
->ddnsKey
= NULL
;
3275 return( mStatus_NoError
);
3282 //===========================================================================================================================
3284 //===========================================================================================================================
3286 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
3289 HANDLE threadHandle
;
3293 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
3295 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3296 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3298 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3299 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3300 require_noerr( err
, exit
);
3302 inMDNS
->p
->initStatus
= mStatus_Invalid
;
3304 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3305 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3307 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
3308 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
3309 require_noerr( err
, exit
);
3311 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
3312 err
= translate_errno( result
== WAIT_OBJECT_0
, (mStatus
) GetLastError(), kUnknownErr
);
3313 require_noerr( err
, exit
);
3314 err
= inMDNS
->p
->initStatus
;
3315 require_noerr( err
, exit
);
3318 if( inMDNS
->p
->initEvent
)
3320 CloseHandle( inMDNS
->p
->initEvent
);
3321 inMDNS
->p
->initEvent
= 0;
3323 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
3327 //===========================================================================================================================
3329 //===========================================================================================================================
3331 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
3333 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3334 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3336 if( inMDNS
->p
->cancelEvent
)
3341 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
3342 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3344 if( inMDNS
->p
->quitEvent
)
3346 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
3347 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
3350 return( mStatus_NoError
);
3353 //===========================================================================================================================
3355 //===========================================================================================================================
3357 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
3369 m
= (mDNS
*) inParam
;
3370 err
= ProcessingThreadInitialize( m
);
3376 // Set up the list of objects we'll be waiting on.
3380 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
3381 require_noerr( err
, exit
);
3383 // Main processing loop.
3385 gWaitListChanged
= FALSE
;
3389 // Give the mDNS core a chance to do its work and determine next event time.
3391 mDNSs32 interval
= mDNS_Execute(m
) - mDNS_TimeNow(m
);
3393 if ( gWaitListChanged
)
3398 if (m
->p
->idleThreadCallback
)
3400 interval
= m
->p
->idleThreadCallback(m
, interval
);
3402 if (interval
< 0) interval
= 0;
3403 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
3404 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
3406 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3408 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
3409 check( result
!= WAIT_FAILED
);
3411 if ( result
!= WAIT_FAILED
)
3413 if( result
== WAIT_TIMEOUT
)
3415 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3417 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
3420 else if( result
== kWaitListCancelEvent
)
3422 // Cancel event. Set the done flag and break to exit.
3424 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
3428 else if( result
== kWaitListInterfaceListChangedEvent
)
3430 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3432 ProcessingThreadInterfaceListChanged( m
);
3435 else if( result
== kWaitListWakeupEvent
)
3437 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3439 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
3442 else if ( result
== kWaitListComputerDescriptionEvent
)
3445 // The computer description might have changed
3447 ProcessingThreadComputerDescriptionChanged( m
);
3450 else if ( result
== kWaitListTCPIPEvent
)
3453 // The TCP/IP might have changed
3455 ProcessingThreadTCPIPConfigChanged( m
);
3458 else if ( result
== kWaitListDynDNSEvent
)
3461 // The DynDNS config might have changed
3463 ProcessingThreadDynDNSConfigChanged( m
);
3470 // Socket data available event. Determine which socket and process the packet.
3472 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
3473 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
3474 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
3475 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
3477 HANDLE signaledObject
;
3479 mDNSInterfaceData
* ifd
;
3480 mDNSTCPConnectionData
* tcd
;
3482 signaledObject
= waitList
[ waitItemIndex
];
3484 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3485 if ( m
->p
->unicastSock4ReadEvent
== signaledObject
)
3487 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock4
);
3492 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3493 if ( m
->p
->unicastSock6ReadEvent
== signaledObject
)
3495 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock6
);
3500 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3502 if( ifd
->readPendingEvent
== signaledObject
)
3504 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
3509 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3511 if ( tcd
->pendingEvent
== signaledObject
)
3513 mDNSBool connect
= FALSE
;
3515 if ( !tcd
->connected
)
3517 tcd
->connected
= mDNStrue
;
3521 tcd
->callback( ( int ) tcd
->sock
, tcd
->context
, connect
);
3533 // Unexpected wait result.
3535 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
3542 err
= ProcessingThreadInitialize( m
);
3548 // Release the wait list.
3558 // Signal the quit event to indicate that the thread is finished.
3561 wasSet
= SetEvent( m
->p
->quitEvent
);
3562 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3564 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3565 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3567 _endthreadex_compat( 0 );
3571 //===========================================================================================================================
3572 // ProcessingThreadInitialize
3573 //===========================================================================================================================
3575 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
3580 inMDNS
->p
->threadID
= GetCurrentThreadId();
3582 err
= SetupInterfaceList( inMDNS
);
3583 require_noerr( err
, exit
);
3585 err
= dDNS_Setup( inMDNS
);
3586 require_noerr( err
, exit
);
3588 err
= dDNS_InitDNSConfig( inMDNS
);
3589 require_noerr( err
, exit
);
3595 TearDownInterfaceList( inMDNS
);
3597 inMDNS
->p
->initStatus
= err
;
3599 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
3600 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3604 //===========================================================================================================================
3605 // ProcessingThreadSetupWaitList
3606 //===========================================================================================================================
3608 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
3613 HANDLE
* waitItemPtr
;
3614 mDNSInterfaceData
* ifd
;
3615 mDNSTCPConnectionData
* tcd
;
3617 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
3620 check( outWaitList
);
3621 check( outWaitListCount
);
3623 // Allocate an array to hold all the objects to wait on.
3625 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->interfaceCount
+ gTCPConnections
;
3626 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
3627 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
3628 waitItemPtr
= waitList
;
3630 // Add the fixed wait items to the beginning of the list.
3632 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
3633 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
3634 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
3635 *waitItemPtr
++ = inMDNS
->p
->descChangedEvent
;
3636 *waitItemPtr
++ = inMDNS
->p
->tcpipChangedEvent
;
3637 *waitItemPtr
++ = inMDNS
->p
->ddnsChangedEvent
;
3639 // Append all the dynamic wait items to the list.
3640 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3641 *waitItemPtr
++ = inMDNS
->p
->unicastSock4ReadEvent
;
3644 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3645 *waitItemPtr
++ = inMDNS
->p
->unicastSock6ReadEvent
;
3648 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3650 *waitItemPtr
++ = ifd
->readPendingEvent
;
3653 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3655 *waitItemPtr
++ = tcd
->pendingEvent
;
3658 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
3660 *outWaitList
= waitList
;
3661 *outWaitListCount
= waitListCount
;
3663 err
= mStatus_NoError
;
3670 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
3674 //===========================================================================================================================
3675 // ProcessingThreadProcessPacket
3676 //===========================================================================================================================
3678 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
)
3681 const mDNSInterfaceID iid
= inIFD
? inIFD
->interfaceInfo
.InterfaceID
: NULL
;
3682 LPFN_WSARECVMSG recvMsgPtr
;
3688 struct sockaddr_storage addr
;
3694 check( IsValidSocket( inSock
) );
3696 // Set up the default in case the packet info options are not supported or reported correctly.
3700 recvMsgPtr
= inIFD
->wsaRecvMsgFunctionPtr
;
3701 dstAddr
= inIFD
->defaultAddr
;
3702 dstPort
= MulticastDNSPort
;
3705 else if ( inSock
== inMDNS
->p
->unicastSock4
)
3707 recvMsgPtr
= inMDNS
->p
->unicastSock4RecvMsgPtr
;
3708 dstAddr
= inMDNS
->p
->unicastSock4DestAddr
;
3709 dstPort
= zeroIPPort
;
3712 else if ( inSock
== inMDNS
->p
->unicastSock6
)
3714 recvMsgPtr
= inMDNS
->p
->unicastSock6RecvMsgPtr
;
3715 dstAddr
= inMDNS
->p
->unicastSock6DestAddr
;
3716 dstPort
= zeroIPPort
;
3721 dlog( kDebugLevelError
, DEBUG_NAME
"packet received on unknown socket\n" );
3725 #if( !TARGET_OS_WINDOWS_CE )
3730 uint8_t controlBuffer
[ 128 ];
3732 LPWSACMSGHDR header
;
3734 // Set up the buffer and read the packet.
3736 msg
.name
= (LPSOCKADDR
) &addr
;
3737 msg
.namelen
= (INT
) sizeof( addr
);
3738 buf
.buf
= (char *) &packet
;
3739 buf
.len
= (u_long
) sizeof( packet
);
3740 msg
.lpBuffers
= &buf
;
3741 msg
.dwBufferCount
= 1;
3742 msg
.Control
.buf
= (char *) controlBuffer
;
3743 msg
.Control
.len
= (u_long
) sizeof( controlBuffer
);
3746 err
= recvMsgPtr( inSock
, &msg
, &size
, NULL
, NULL
);
3747 err
= translate_errno( err
== 0, (OSStatus
) GetLastError(), kUnknownErr
);
3748 require_noerr( err
, exit
);
3751 // Parse the control information. Reject packets received on the wrong interface.
3753 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
3755 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3757 IN_PKTINFO
* ipv4PacketInfo
;
3759 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3763 require_action( ipv4PacketInfo
->ipi_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
3766 dstAddr
.type
= mDNSAddrType_IPv4
;
3767 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3769 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3771 IN6_PKTINFO
* ipv6PacketInfo
;
3773 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3777 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( inIFD
->index
- kIPv6IfIndexBase
), exit
, err
= kMismatchErr
);
3780 dstAddr
.type
= mDNSAddrType_IPv6
;
3781 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3790 addrSize
= sizeof( addr
);
3791 n
= recvfrom( inSock
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
3792 err
= translate_errno( n
> 0, errno_compat(), kUnknownErr
);
3793 require_noerr( err
, exit
);
3795 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
3797 // Dispatch the packet to mDNS.
3799 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3800 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
3801 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3802 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3806 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &inIFD
->interfaceInfo
.ip
, (int) inIFD
->index
);
3809 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3811 end
= ( (mDNSu8
*) &packet
) + n
;
3812 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3818 //===========================================================================================================================
3819 // ProcessingThreadInterfaceListChanged
3820 //===========================================================================================================================
3822 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
3826 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3829 if (inMDNS
->p
->interfaceListChangedCallback
)
3831 inMDNS
->p
->interfaceListChangedCallback(inMDNS
);
3834 mDNSPlatformLock( inMDNS
);
3836 // Tear down the existing interfaces and set up new ones using the new IP info.
3838 err
= TearDownInterfaceList( inMDNS
);
3841 err
= SetupInterfaceList( inMDNS
);
3844 err
= dDNS_Setup( inMDNS
);
3847 // so that LLQs are restarted against the up to date name servers
3849 mDNS_UpdateLLQs( inMDNS
);
3851 mDNSPlatformUnlock( inMDNS
);
3853 // Inform clients of the change.
3855 if( inMDNS
->MainCallback
)
3857 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
3860 // Force mDNS to update.
3862 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
3866 //===========================================================================================================================
3867 // ProcessingThreadComputerDescriptionChanged
3868 //===========================================================================================================================
3869 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
*inMDNS
)
3873 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3876 mDNSPlatformLock( inMDNS
);
3879 SetupNiceName( inMDNS
);
3881 if (inMDNS
->p
->hostDescriptionChangedCallback
)
3883 inMDNS
->p
->hostDescriptionChangedCallback(inMDNS
);
3886 // and reset the event handler
3887 if ((inMDNS
->p
->descKey
!= NULL
) && (inMDNS
->p
->descChangedEvent
))
3889 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3893 mDNSPlatformUnlock( inMDNS
);
3897 //===========================================================================================================================
3898 // ProcessingThreadTCPIPConfigChanged
3899 //===========================================================================================================================
3900 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
)
3904 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3907 mDNSPlatformLock( inMDNS
);
3909 err
= dDNS_Setup( inMDNS
);
3912 // so that LLQs are restarted against the up to date name servers
3914 mDNS_UpdateLLQs( inMDNS
);
3916 // and reset the event handler
3918 if ( ( inMDNS
->p
->tcpipKey
!= NULL
) && ( inMDNS
->p
->tcpipChangedEvent
) )
3920 err
= RegNotifyChangeKeyValue( inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3924 mDNSPlatformUnlock( inMDNS
);
3928 //===========================================================================================================================
3929 // ProcessingThreadDynDNSConfigChanged
3930 //===========================================================================================================================
3931 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
*inMDNS
)
3935 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3938 mDNSPlatformLock( inMDNS
);
3940 err
= dDNS_Setup( inMDNS
);
3943 // so that LLQs are restarted against the up to date name servers
3945 mDNS_UpdateLLQs( inMDNS
);
3947 // and reset the event handler
3949 if ((inMDNS
->p
->ddnsKey
!= NULL
) && (inMDNS
->p
->ddnsChangedEvent
))
3951 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3955 mDNSPlatformUnlock( inMDNS
);
3961 #pragma mark == Utilities ==
3964 //===========================================================================================================================
3966 //===========================================================================================================================
3968 int getifaddrs( struct ifaddrs
**outAddrs
)
3972 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
3974 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3975 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3977 if( !gIPHelperLibraryInstance
)
3979 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
3980 if( gIPHelperLibraryInstance
)
3982 gGetAdaptersAddressesFunctionPtr
=
3983 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
3984 if( !gGetAdaptersAddressesFunctionPtr
)
3988 ok
= FreeLibrary( gIPHelperLibraryInstance
);
3989 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
3990 gIPHelperLibraryInstance
= NULL
;
3995 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3996 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
3998 if( !gGetAdaptersAddressesFunctionPtr
|| ( ( err
= getifaddrs_ipv6( outAddrs
) ) != mStatus_NoError
) )
4000 err
= getifaddrs_ipv4( outAddrs
);
4001 require_noerr( err
, exit
);
4004 #elif( !TARGET_OS_WINDOWS_CE )
4006 err
= getifaddrs_ipv4( outAddrs
);
4007 require_noerr( err
, exit
);
4011 err
= getifaddrs_ce( outAddrs
);
4012 require_noerr( err
, exit
);
4020 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
4021 //===========================================================================================================================
4023 //===========================================================================================================================
4025 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
4030 struct ifaddrs
* head
;
4031 struct ifaddrs
** next
;
4032 IP_ADAPTER_ADDRESSES
* iaaList
;
4034 IP_ADAPTER_ADDRESSES
* iaa
;
4036 struct ifaddrs
* ifa
;
4038 check( gGetAdaptersAddressesFunctionPtr
);
4044 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
4045 // This loops to handle the case where the interface changes in the window after getting the size, but before the
4046 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
4048 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
4053 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
4054 check( err
== ERROR_BUFFER_OVERFLOW
);
4055 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
4057 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
4058 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
4060 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
4061 if( err
== ERROR_SUCCESS
) break;
4066 require( i
< 100, exit
);
4067 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
4070 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
4073 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
4075 IP_ADAPTER_PREFIX
* firstPrefix
;
4077 if( iaa
->IfIndex
> 0xFFFFFF )
4079 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
4081 if( iaa
->Ipv6IfIndex
> 0xFF )
4083 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
4086 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
4087 // following code to crash when iterating through the prefix list. This seems
4088 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
4089 // This shouldn't happen according to Microsoft docs which states:
4091 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
4093 // So the data structure seems to be corrupted when we return from
4094 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
4095 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
4096 // modify iaa to have the correct values.
4098 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
4100 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
4101 firstPrefix
= iaa
->FirstPrefix
;
4109 // Skip psuedo and tunnel interfaces.
4111 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
4116 // Add each address as a separate interface to emulate the way getifaddrs works.
4118 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
4122 IP_ADAPTER_PREFIX
* prefix
;
4125 family
= addr
->Address
.lpSockaddr
->sa_family
;
4126 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
4128 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4129 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4132 next
= &ifa
->ifa_next
;
4136 size
= strlen( iaa
->AdapterName
) + 1;
4137 ifa
->ifa_name
= (char *) malloc( size
);
4138 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4139 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
4141 // Get interface flags.
4144 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
4145 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
4146 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
4147 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
4150 // <rdar://problem/4045657> Interface index being returned is 512
4152 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
4153 // This code used to shift the IPv4 index up to ensure uniqueness between
4154 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
4155 // then see interface indexes passed back that don't correspond to anything
4156 // that is seen in Win32 APIs or command line tools like "route". As a relatively
4157 // small percentage of developers are actively using IPv6, it seems to
4158 // make sense to make our use of IPv4 as confusion free as possible.
4159 // So now, IPv6 interface indexes will be shifted up by a
4160 // constant value which will serve to uniquely identify them, and we will
4161 // leave IPv4 interface indexes unmodified.
4165 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
4166 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
4176 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
4177 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4178 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
4184 check( ifa
->ifa_addr
);
4186 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
4189 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
4191 if( prefixIndex
== addrIndex
)
4193 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
4194 prefixLength
= prefix
->PrefixLength
;
4202 struct sockaddr_in
* sa4
;
4204 require_action( prefixLength
<= 32, exit
, err
= ERROR_INVALID_DATA
);
4206 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
4207 require_action( sa4
, exit
, err
= WSAENOBUFS
);
4209 sa4
->sin_family
= AF_INET
;
4211 if ( prefixLength
!= 0 )
4213 sa4
->sin_addr
.s_addr
= htonl( 0xFFFFFFFFU
<< ( 32 - prefixLength
) );
4219 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv4 prefixLength is 0\n", __ROUTINE__
);
4220 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &index
, (struct sockaddr
*) sa4
);
4221 require_noerr( err
, exit
);
4224 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
4225 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
4231 struct sockaddr_in6
* sa6
;
4236 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
4238 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
4239 require_action( sa6
, exit
, err
= WSAENOBUFS
);
4240 sa6
->sin6_family
= AF_INET6
;
4242 if( prefixLength
== 0 )
4244 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
4248 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
4250 if( len
>= 8 ) maskByte
= 0xFF;
4251 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
4252 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
4254 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
4271 err
= ERROR_SUCCESS
;
4276 freeifaddrs( head
);
4282 return( (int) err
);
4285 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
4287 #if( !TARGET_OS_WINDOWS_CE )
4288 //===========================================================================================================================
4290 //===========================================================================================================================
4292 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
4298 INTERFACE_INFO
* buffer
;
4299 INTERFACE_INFO
* tempBuffer
;
4300 INTERFACE_INFO
* ifInfo
;
4303 struct ifaddrs
* head
;
4304 struct ifaddrs
** next
;
4305 struct ifaddrs
* ifa
;
4307 sock
= INVALID_SOCKET
;
4312 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4313 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4314 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4316 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4317 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4318 require_noerr( err
, exit
);
4321 size
= 16 * sizeof( INTERFACE_INFO
);
4324 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
4325 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
4326 buffer
= tempBuffer
;
4328 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
4335 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
4337 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
4339 check( actualSize
<= size
);
4340 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
4341 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
4343 // Process the raw interface list and build a linked list of IPv4 interfaces.
4345 for( i
= 0; i
< n
; ++i
)
4347 ifInfo
= &buffer
[ i
];
4348 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
4353 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4354 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4357 next
= &ifa
->ifa_next
;
4361 ifa
->ifa_name
= (char *) malloc( 16 );
4362 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4363 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4365 // Get interface flags.
4367 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4371 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
4373 struct sockaddr_in
* sa4
;
4375 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4376 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4377 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4378 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4380 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4382 // <rdar://problem/4076478> Service won't start on Win2K. The address
4383 // family field was not being initialized.
4385 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4386 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4387 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &ifa
->ifa_extra
.index
, ifa
->ifa_netmask
);
4388 require_noerr( err
, exit
);
4392 // Emulate an interface index.
4394 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4410 freeifaddrs( head
);
4416 if( sock
!= INVALID_SOCKET
)
4418 closesocket( sock
);
4422 #endif // !TARGET_OS_WINDOWS_CE )
4424 #if( TARGET_OS_WINDOWS_CE )
4425 //===========================================================================================================================
4427 //===========================================================================================================================
4429 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
4435 SOCKET_ADDRESS_LIST
* addressList
;
4436 struct ifaddrs
* head
;
4437 struct ifaddrs
** next
;
4438 struct ifaddrs
* ifa
;
4442 sock
= kInvalidSocketRef
;
4447 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4449 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4450 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4451 require_noerr( err
, exit
);
4453 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4454 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4456 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4459 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
4460 require_action( size
> 0, exit
, err
= -1 );
4463 buffer
= calloc( 1, size
);
4464 require_action( buffer
, exit
, err
= -1 );
4466 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4468 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
4469 require_noerr( err
, exit
);
4470 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
4472 // Process the raw interface list and build a linked list of interfaces.
4474 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4476 n
= addressList
->iAddressCount
;
4481 for( i
= 0; i
< n
; ++i
)
4483 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4484 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4487 next
= &ifa
->ifa_next
;
4491 ifa
->ifa_name
= (char *) malloc( 16 );
4492 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4493 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4495 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4497 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
4501 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
4505 struct sockaddr_in
* sa4
;
4507 sa4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
4508 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4509 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4510 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4531 freeifaddrs( head
);
4537 if( sock
!= INVALID_SOCKET
)
4539 closesocket( sock
);
4543 #endif // TARGET_OS_WINDOWS_CE )
4545 //===========================================================================================================================
4547 //===========================================================================================================================
4549 void freeifaddrs( struct ifaddrs
*inIFAs
)
4554 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4556 for( p
= inIFAs
; p
; p
= q
)
4562 free( p
->ifa_name
);
4567 free( p
->ifa_addr
);
4570 if( p
->ifa_netmask
)
4572 free( p
->ifa_netmask
);
4573 p
->ifa_netmask
= NULL
;
4575 if( p
->ifa_broadaddr
)
4577 free( p
->ifa_broadaddr
);
4578 p
->ifa_broadaddr
= NULL
;
4580 if( p
->ifa_dstaddr
)
4582 free( p
->ifa_dstaddr
);
4583 p
->ifa_dstaddr
= NULL
;
4587 free( p
->ifa_data
);
4595 //===========================================================================================================================
4596 // GetPrimaryInterface
4597 //===========================================================================================================================
4600 GetPrimaryInterface()
4602 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4604 BOOL bOrder
= FALSE
;
4608 unsigned long int i
;
4610 // Find out how big our buffer needs to be.
4612 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4613 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4615 // Allocate the memory for the table
4617 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4618 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4620 // Now get the table.
4622 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4623 require_noerr( err
, exit
);
4626 // Search for the row in the table we want.
4628 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4630 // Look for a default route
4632 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4634 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4639 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4640 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4646 if ( pIpForwardTable
!= NULL
)
4648 free( pIpForwardTable
);
4655 //===========================================================================================================================
4656 // AddressToIndexAndMask
4657 //===========================================================================================================================
4660 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4662 // Before calling AddIPAddress we use GetIpAddrTable to get
4663 // an adapter to which we can add the IP.
4665 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4667 mStatus err
= mStatus_UnknownErr
;
4670 // For now, this is only for IPv4 addresses. That is why we can safely cast
4671 // addr's to sockaddr_in.
4673 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4675 // Make an initial call to GetIpAddrTable to get the
4676 // necessary size into the dwSize variable
4678 for ( i
= 0; i
< 100; i
++ )
4680 err
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
4682 if ( err
!= ERROR_INSUFFICIENT_BUFFER
)
4687 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4688 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4691 require_noerr( err
, exit
);
4693 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4695 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4697 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4698 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4699 err
= mStatus_NoError
;
4708 free( pIPAddrTable
);
4715 //===========================================================================================================================
4716 // CanReceiveUnicast
4717 //===========================================================================================================================
4719 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4723 struct sockaddr_in addr
;
4725 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4727 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4728 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4729 ok
= IsValidSocket( sock
);
4732 memset( &addr
, 0, sizeof( addr
) );
4733 addr
.sin_family
= AF_INET
;
4734 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4735 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4737 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4738 close_compat( sock
);
4741 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4746 //===========================================================================================================================
4748 //===========================================================================================================================
4750 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4752 struct ifaddrs
* addrs
= NULL
;
4753 struct ifaddrs
* p
= NULL
;
4755 mDNSBool ret
= mDNSfalse
;
4757 // For now, only works for IPv4 interfaces
4759 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4761 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4763 err
= getifaddrs_ipv4( &addrs
);
4764 require_noerr( err
, exit
);
4766 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4768 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4769 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4771 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4781 freeifaddrs( addrs
);
4788 //===========================================================================================================================
4789 // GetWindowsVersionString
4790 //===========================================================================================================================
4792 OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4794 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4795 #define VER_PLATFORM_WIN32_CE 3
4799 OSVERSIONINFO osInfo
;
4801 const char * versionString
;
4807 versionString
= "unknown Windows version";
4809 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4810 ok
= GetVersionEx( &osInfo
);
4811 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4812 require_noerr( err
, exit
);
4814 platformID
= osInfo
.dwPlatformId
;
4815 majorVersion
= osInfo
.dwMajorVersion
;
4816 minorVersion
= osInfo
.dwMinorVersion
;
4817 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4819 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4821 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4823 versionString
= "Windows 95";
4825 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4827 versionString
= "Windows 95 SP1";
4829 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4831 versionString
= "Windows 95 OSR2";
4833 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4835 versionString
= "Windows 98";
4837 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4839 versionString
= "Windows 98 SP1";
4841 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4843 versionString
= "Windows 98 SE";
4845 else if( minorVersion
== 90 )
4847 versionString
= "Windows ME";
4850 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4852 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4854 versionString
= "Windows NT 3.51";
4856 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4858 versionString
= "Windows NT 4";
4860 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4862 versionString
= "Windows 2000";
4864 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4866 versionString
= "Windows XP";
4868 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4870 versionString
= "Windows Server 2003";
4873 else if( platformID
== VER_PLATFORM_WIN32_CE
)
4875 versionString
= "Windows CE";
4879 if( inBuffer
&& ( inBufferSize
> 0 ) )
4882 strncpy( inBuffer
, versionString
, inBufferSize
);
4883 inBuffer
[ inBufferSize
] = '\0';
4889 //===========================================================================================================================
4891 //===========================================================================================================================
4894 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
4900 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
4911 *string
= (char*) malloc( *stringLen
);
4912 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
4914 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
4918 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
4920 require_noerr_quiet( err
, exit
);
4924 DWORD dwSize
= sizeof( DWORD
);
4926 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
4938 //===========================================================================================================================
4940 //===========================================================================================================================
4942 static mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
4944 struct sockaddr_in6 sa6
;
4945 struct sockaddr_in sa4
;
4949 sa6
.sin6_family
= AF_INET6
;
4950 dwSize
= sizeof( sa6
);
4952 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
4954 if ( err
== mStatus_NoError
)
4956 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa6
);
4957 require_noerr( err
, exit
);
4961 sa4
.sin_family
= AF_INET
;
4962 dwSize
= sizeof( sa4
);
4964 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
4965 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
4966 require_noerr( err
, exit
);
4968 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa4
);
4969 require_noerr( err
, exit
);
4978 //===========================================================================================================================
4980 //===========================================================================================================================
4982 mDNSlocal
struct ifaddrs
*
4983 myGetIfAddrs(int refresh
)
4985 static struct ifaddrs
*ifa
= NULL
;
5002 //===========================================================================================================================
5004 //===========================================================================================================================
5007 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
5009 #if( defined( UNICODE ) || defined( _UNICODE ) )
5013 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
5014 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5015 require_noerr( err
, exit
);
5020 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
5025 //===========================================================================================================================
5026 // WindowsLatin1toUTF8
5027 //===========================================================================================================================
5030 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
5038 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
5040 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
5041 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5042 require_noerr( err
, exit
);
5044 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
5045 require_action( utf16
, exit
, err
= kNoMemoryErr
);
5047 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
5048 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5049 require_noerr( err
, exit
);
5051 // Now convert the temporary UTF-16 to UTF-8.
5053 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
5054 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5055 require_noerr( err
, exit
);
5058 if( utf16
) free( utf16
);
5063 //===========================================================================================================================
5064 // ConvertUTF8ToLsaString
5065 //===========================================================================================================================
5068 MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
)
5076 output
->Buffer
= NULL
;
5078 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, NULL
, 0 );
5079 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
5080 require_noerr( err
, exit
);
5082 output
->Length
= (USHORT
)( size
* sizeof( wchar_t ) );
5083 output
->Buffer
= (PWCHAR
) malloc( output
->Length
);
5084 require_action( output
->Buffer
, exit
, err
= mStatus_NoMemoryErr
);
5085 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, output
->Buffer
, size
);
5086 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
5087 require_noerr( err
, exit
);
5089 // We're going to subtrace one wchar_t from the size, because we didn't
5090 // include it when we encoded the string
5092 output
->MaximumLength
= output
->Length
;
5093 output
->Length
-= sizeof( wchar_t );
5097 if ( err
&& output
->Buffer
)
5099 free( output
->Buffer
);
5100 output
->Buffer
= NULL
;
5107 //===========================================================================================================================
5108 // ConvertLsaStringToUTF8
5109 //===========================================================================================================================
5112 MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
)
5115 OSStatus err
= kNoErr
;
5117 // The Length field of this structure holds the number of bytes,
5118 // but WideCharToMultiByte expects the number of wchar_t's. So
5119 // we divide by sizeof(wchar_t) to get the correct number.
5121 size
= (size_t) WideCharToMultiByte(CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), NULL
, 0, NULL
, NULL
);
5122 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
5123 require_noerr( err
, exit
);
5125 // Ensure that we have enough space (Add one for trailing '\0')
5127 require_action( ( size
+ 1 ) <= len
, exit
, err
= mStatus_NoMemoryErr
);
5129 // Convert the string
5131 size
= (size_t) WideCharToMultiByte( CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), output
, (int) size
, NULL
, NULL
);
5132 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
5133 require_noerr( err
, exit
);
5135 // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
5136 // although it does return the correct size
5138 output
[size
] = '\0';
5146 //===========================================================================================================================
5147 // FreeTCPConnectionData
5148 //===========================================================================================================================
5151 FreeTCPConnectionData( mDNSTCPConnectionData
* data
)
5155 if ( data
->pendingEvent
)
5157 CloseHandle( data
->pendingEvent
);
5160 if ( data
->sock
!= INVALID_SOCKET
)
5162 closesocket( data
->sock
);