1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
20 Revision 1.107.2.1 2006/08/29 06:24:39 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.107 2006/03/19 02:00:13 cheshire
24 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
26 Revision 1.106 2006/02/26 19:31:05 herscher
27 <rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency. The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it. 2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
29 Revision 1.105 2005/11/27 20:21:16 herscher
30 <rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
32 Revision 1.104 2005/10/19 19:42:59 herscher
33 <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.
35 Revision 1.103 2005/10/18 06:13:20 herscher
36 <rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
38 Revision 1.102 2005/10/05 20:55:14 herscher
39 <rdar://problem/4096464> Don't call SetLLRoute on loopback interface
41 Revision 1.101 2005/10/05 18:05:28 herscher
42 <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.
44 Revision 1.100 2005/09/29 06:36:00 herscher
45 Change check( err ) to check( !err ). This was a typo that was introduced in a previous checkin.
47 Revision 1.99 2005/09/29 06:31:46 herscher
48 <rdar://problem/4278934> Fall back to calling getifaddrs_ipv4 if getifaddrs_ipv6 fails
50 Revision 1.98 2005/09/24 01:11:56 cheshire
51 Add comment about GetWindowsVersionString
53 Revision 1.97 2005/09/22 07:10:44 herscher
54 <rdar://problem/4263713> Don't send domain enumeration query if domain is empty string or "."
56 Revision 1.96 2005/09/22 07:06:06 herscher
57 <rdar://problem/4252581> Don't loop uncontrollably upon detection of error in main event loop
59 Revision 1.95 2005/09/11 22:51:40 herscher
60 <rdar://problem/4249284> Obtain Hostname by using GetComputerNameEx, rather than gethostname.
62 Revision 1.94 2005/09/11 21:43:15 herscher
63 <rdar://problem/4245949> Don't create HINFO records on Windows
65 Revision 1.93 2005/07/15 06:06:40 shersche
66 <rdar://problem/4165134> Change all WinSock allocation loops to bail out after 100 tries to eliminate the possibility of any infinite loops
68 Revision 1.92 2005/07/11 20:32:17 shersche
69 <rdar://problem/4175515> Fix crash when logging into Cisco VPN
71 Revision 1.91 2005/04/25 21:34:28 shersche
72 <rdar://problem/4096465> Wide-Area services don't disappear when interface goes away
74 Revision 1.90 2005/04/25 21:18:08 shersche
75 <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.
77 Revision 1.89 2005/04/22 07:32:24 shersche
78 <rdar://problem/4092108> PPP connection disables Bonjour .local lookups
79 <rdar://problem/4093944> mDNSResponder ignores Point-to-Point interfaces
81 Revision 1.88 2005/04/05 03:53:03 shersche
82 <rdar://problem/4066485> Registering with shared secret key doesn't work.
84 Revision 1.87 2005/04/03 08:03:12 shersche
85 <rdar://problem/4076478> mDNSResponder won't start on Windows 2000.
87 Revision 1.86 2005/03/30 07:37:14 shersche
88 Use prefix to compute IPv4 subnet mask, falling back to calling AddressToIndexAndMask only if prefix is zero.
90 Revision 1.85 2005/03/30 07:34:52 shersche
91 <rdar://problem/4045657> Interface index being returned is 512
93 Revision 1.84 2005/03/29 19:19:47 shersche
94 <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.
96 Revision 1.83 2005/03/07 18:27:42 shersche
97 <rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
99 Revision 1.82 2005/03/06 05:20:24 shersche
100 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
102 Revision 1.81 2005/03/04 22:44:53 shersche
103 <rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
105 Revision 1.80 2005/03/03 21:07:38 shersche
106 <rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
108 Revision 1.79 2005/03/03 02:29:00 shersche
109 Use the RegNames.h header file for registry key names
111 Revision 1.78 2005/03/02 04:04:17 shersche
112 Support for multiple browse domains
114 Revision 1.77 2005/02/25 20:02:18 shersche
115 <rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
117 Revision 1.76 2005/02/23 02:59:20 shersche
118 <rdar://problem/4013482> Check to see if locks have been initialized before using them.
120 Revision 1.75 2005/02/16 02:36:25 shersche
121 <rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
123 Revision 1.74 2005/02/08 06:06:16 shersche
124 <rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
126 Revision 1.73 2005/02/01 19:35:43 ksekar
127 Removed obsolete arguments from mDNS_SetSecretForZone
129 Revision 1.72 2005/02/01 01:38:53 shersche
130 Handle null DynDNS configuration more gracefully
132 Revision 1.71 2005/01/27 22:57:57 cheshire
133 Fix compile errors on gcc4
135 Revision 1.70 2005/01/25 08:12:52 shersche
136 <rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
139 Revision 1.69 2005/01/11 04:39:48 shersche
140 Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
142 Revision 1.68 2005/01/11 02:04:48 shersche
143 Gracefully handle when IPv6 is not installed on a user's machine
145 Revision 1.67 2004/12/18 00:51:52 cheshire
146 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
148 Revision 1.66 2004/12/17 23:37:49 cheshire
149 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
150 (and other repetitive configuration changes)
152 Revision 1.65 2004/12/15 07:34:45 shersche
153 Add platform support for IPv4 and IPv6 unicast sockets
155 Revision 1.64 2004/12/15 06:06:15 shersche
156 Fix problem in obtaining IPv6 subnet mask
158 Revision 1.63 2004/11/23 03:39:47 cheshire
159 Let interface name/index mapping capability live directly in JNISupport.c,
160 instead of having to call through to the daemon via IPC to get this information.
162 Revision 1.62 2004/11/12 03:16:41 rpantos
163 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
165 Revision 1.61 2004/11/05 22:54:38 shersche
166 Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
167 Submitted by: Pavel Repin <prepin@gmail.com>
169 Revision 1.60 2004/11/05 22:41:56 shersche
170 Determine subnet mask when populating network interface data structures
171 Submitted by: Pavel Repin <prepin@gmail.com>
174 Revision 1.59 2004/10/28 03:24:42 cheshire
175 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
177 Revision 1.58 2004/10/16 00:17:01 cheshire
178 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
180 Revision 1.57 2004/10/11 21:53:15 shersche
181 <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().
184 Revision 1.56 2004/09/26 23:20:36 ksekar
185 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
187 Revision 1.55 2004/09/21 21:02:57 cheshire
188 Set up ifname before calling mDNS_RegisterInterface()
190 Revision 1.54 2004/09/17 01:08:57 cheshire
191 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
192 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
193 declared in that file are ONLY appropriate to single-address-space embedded applications.
194 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
196 Revision 1.53 2004/09/17 00:19:11 cheshire
197 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
199 Revision 1.52 2004/09/16 00:24:50 cheshire
200 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
202 Revision 1.51 2004/09/14 23:42:37 cheshire
203 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
205 Revision 1.50 2004/08/25 23:36:56 shersche
206 <rdar://problem/3658379> Remove code that retrieves TTL from received packets
209 Revision 1.49 2004/08/25 16:43:29 ksekar
210 Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
213 Revision 1.48 2004/08/14 03:22:43 cheshire
214 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
215 Add GetUserSpecifiedDDNSName() routine
216 Convert ServiceRegDomain to domainname instead of C string
217 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
219 Revision 1.47 2004/08/06 17:33:02 shersche
220 <rdar://problem/3753797> Put correct length of string in first byte of nicelabel
223 Revision 1.46 2004/08/05 05:43:01 shersche
224 <rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
227 Revision 1.45 2004/07/26 22:49:31 ksekar
228 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
230 Revision 1.44 2004/07/26 05:42:50 shersche
231 use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
233 Revision 1.43 2004/07/13 21:24:25 rpantos
234 Fix for <rdar://problem/3701120>.
236 Revision 1.42 2004/06/24 15:23:24 shersche
237 Add InterfaceListChanged callback. This callback is used in Service.c to add link local routes to the routing table
238 Submitted by: herscher
240 Revision 1.41 2004/06/18 05:22:16 rpantos
241 Integrate Scott's changes
243 Revision 1.40 2004/05/26 09:06:07 bradley
244 Retry while building the interface list if it returns an error since the two-step process required to
245 get the interface list could allow a subsequent interface change to come in that window and change the
246 needed size after getting the size, but before getting the list, causing it to return an error.
247 Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
249 Revision 1.39 2004/05/18 23:51:27 cheshire
250 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
252 Revision 1.38 2004/05/13 04:57:48 ksekar
253 Removed unnecessary FreeSearchList function
255 Revision 1.37 2004/05/13 04:54:20 ksekar
256 Unified list copy/free code. Added symetric list for
258 Revision 1.36 2004/05/12 22:03:09 ksekar
259 Made GetSearchDomainList a true platform-layer call (declaration moved
260 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
261 only on non-OSX platforms. Changed call to return a copy of the list
262 to avoid shared memory issues. Added a routine to free the list.
264 Revision 1.35 2004/04/21 02:49:12 cheshire
265 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
267 Revision 1.34 2004/04/15 01:00:05 bradley
268 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
269 without .local name resolving support will need to manually query for A/AAAA records as needed.
271 Revision 1.33 2004/04/14 23:09:29 ksekar
272 Support for TSIG signed dynamic updates.
274 Revision 1.32 2004/04/09 17:40:26 cheshire
275 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
277 Revision 1.31 2004/04/09 00:40:46 bradley
278 Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
280 Revision 1.30 2004/04/09 00:33:58 bradley
281 Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
283 Revision 1.29 2004/03/15 02:07:46 bradley
284 Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
285 handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
286 does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
288 Revision 1.28 2004/03/07 00:26:39 bradley
289 Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
290 Added count assert when building the wait list to catch underruns/overruns if the code is changed.
292 Revision 1.27 2004/01/30 02:44:32 bradley
293 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
294 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
295 are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
296 (it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
297 software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
298 reporting HINFO records with the Windows and mDNSResponder version information.
300 Revision 1.26 2004/01/24 04:59:16 cheshire
301 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
303 Revision 1.25 2003/11/14 20:59:09 cheshire
304 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
305 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
307 Revision 1.24 2003/10/24 23:23:02 bradley
308 Removed legacy port 53 support as it is no longer needed.
310 Revision 1.23 2003/10/14 03:26:12 bradley
311 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
313 Revision 1.22 2003/08/20 06:21:25 bradley
314 Updated to latest internal version of the mDNSWindows platform layer: Added support
315 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
316 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
317 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
318 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
319 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
320 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
321 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
322 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
324 Revision 1.21 2003/08/18 23:09:57 cheshire
325 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
327 Revision 1.20 2003/08/12 19:56:27 cheshire
330 Revision 1.19 2003/08/05 23:58:18 cheshire
331 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
332 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
334 Revision 1.18 2003/07/23 21:16:30 cheshire
335 Removed a couple of debugfs
337 Revision 1.17 2003/07/23 02:23:01 cheshire
338 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
339 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
341 Revision 1.16 2003/07/19 03:15:16 cheshire
342 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
343 and add the obvious trivial implementations to each platform support layer
345 Revision 1.15 2003/07/02 21:20:04 cheshire
346 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
348 Revision 1.14 2003/05/26 03:21:30 cheshire
349 Tidy up address structure naming:
350 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
351 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
352 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
354 Revision 1.13 2003/05/26 03:01:28 cheshire
355 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
357 Revision 1.12 2003/05/06 21:06:05 cheshire
358 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
360 Revision 1.11 2003/05/06 00:00:51 cheshire
361 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
363 Revision 1.10 2003/04/29 00:06:09 cheshire
364 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
366 Revision 1.9 2003/04/26 02:40:01 cheshire
367 Add void LogMsg( const char *format, ... )
369 Revision 1.8 2003/03/22 02:57:44 cheshire
370 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
372 Revision 1.7 2003/03/15 04:40:38 cheshire
373 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
375 Revision 1.6 2003/02/21 01:54:10 cheshire
376 <rdar://problem/3099194> mDNSResponder needs performance improvements
377 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
379 Revision 1.5 2003/02/20 00:59:03 cheshire
380 Brought Windows code up to date so it complies with
381 Josh Graessley's interface changes for IPv6 support.
382 (Actual support for IPv6 on Windows will come later.)
384 Revision 1.4 2002/09/21 20:44:54 zarzycki
387 Revision 1.3 2002/09/20 05:50:45 bradley
388 Multicast DNS platform plugin for Win32
392 - Get unicode name of machine for nice name instead of just the host name.
393 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
394 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
395 - Implement TCP support for truncated packets (only stubs now).
404 #include "CommonServices.h"
405 #include "DebugServices.h"
406 #include "VPCDetect.h"
407 #include "RegNames.h"
410 #include <Iphlpapi.h>
411 #if( !TARGET_OS_WINDOWS_CE )
414 #include <ntsecapi.h>
417 #include "mDNSEmbeddedAPI.h"
419 #include "mDNSWin32.h"
422 #pragma mark == Constants ==
425 //===========================================================================================================================
427 //===========================================================================================================================
429 #define DEBUG_NAME "[mDNSWin32] "
431 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
432 #define MDNS_WINDOWS_ENABLE_IPV4 1
433 #define MDNS_WINDOWS_ENABLE_IPV6 1
434 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
435 #define MDNS_SET_HINFO_STRINGS 0
437 #define kMDNSDefaultName "My Computer"
439 #define kWinSockMajorMin 2
440 #define kWinSockMinorMin 2
442 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
443 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
444 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
445 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
446 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
447 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
448 #define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
450 #define kRegistryMaxKeyLength 255
452 #if( !TARGET_OS_WINDOWS_CE )
453 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
456 #define kIPv6IfIndexBase (10000000L)
458 #define kRetryVPCRate (-100000000)
459 #define kRetryVPCMax (10)
463 #pragma mark == Prototypes ==
466 //===========================================================================================================================
468 //===========================================================================================================================
470 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
471 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
472 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
473 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
474 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
475 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
476 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
477 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
478 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
479 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
480 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
481 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
482 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
483 mDNSlocal mStatus
SetupRetryVPCCheck( mDNS
* const inMDNS
);
484 mDNSlocal mStatus
TearDownRetryVPCCheck( mDNS
* const inMDNS
);
486 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
487 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
488 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
489 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
490 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
491 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
);
492 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
493 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
* inMDNS
);
494 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
);
495 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
* inMDNS
);
496 mDNSlocal
void ProcessingThreadRetryVPCCheck( mDNS
* inMDNS
);
499 // Platform Accessors
505 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
506 struct mDNSPlatformInterfaceInfo
512 typedef struct mDNSTCPConnectionData mDNSTCPConnectionData
;
513 struct mDNSTCPConnectionData
517 TCPConnectionCallback callback
;
520 mDNSTCPConnectionData
* next
;
524 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
525 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
529 typedef struct PolyString PolyString
;
535 PLSA_UNICODE_STRING m_lsa
;
539 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
540 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
543 #if( !TARGET_OS_WINDOWS_CE )
544 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
547 #if( TARGET_OS_WINDOWS_CE )
548 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
551 mDNSlocal DWORD
GetPrimaryInterface();
552 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
553 mDNSlocal mDNSBool
CanReceiveUnicast( void );
554 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
556 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
557 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
558 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
559 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
560 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
561 mDNSlocal OSStatus
MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
);
562 mDNSlocal OSStatus
MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
);
563 mDNSlocal
void FreeTCPConnectionData( mDNSTCPConnectionData
* data
);
570 #pragma mark == Globals ==
573 //===========================================================================================================================
575 //===========================================================================================================================
577 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
578 mDNSs32 mDNSPlatformOneSecond
= 0;
579 mDNSlocal mDNSTCPConnectionData
* gTCPConnectionList
= NULL
;
580 mDNSlocal
int gTCPConnections
= 0;
581 mDNSlocal BOOL gWaitListChanged
= FALSE
;
583 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
586 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
590 PIP_ADAPTER_ADDRESSES inAdapter
,
591 PULONG outBufferSize
);
593 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
594 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
600 #pragma mark == Platform Support ==
603 //===========================================================================================================================
605 //===========================================================================================================================
607 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
612 struct sockaddr_in sa4
;
613 struct sockaddr_in6 sa6
;
617 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
619 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
620 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
622 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
623 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
624 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
625 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
627 // Startup WinSock 2.2 or later.
629 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
630 require_noerr( err
, exit
);
632 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
633 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
635 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
637 // Setup the HINFO HW/SW strings.
639 #if ( MDNS_SET_HINFO_STRINGS )
640 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
642 // Note that GetWindowsVersionString guarantees that the resulting string is always null-terminated,
643 // so the following strlen call is safe
644 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
645 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
647 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
648 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
649 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
650 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
655 inMDNS
->p
->vpcCheckCount
= 0;
656 inMDNS
->p
->vpcCheckEvent
= NULL
;
657 inMDNS
->p
->timersCount
= 0;
659 // Set up the IPv4 unicast socket
661 inMDNS
->p
->unicastSock4
= INVALID_SOCKET
;
662 inMDNS
->p
->unicastSock4ReadEvent
= NULL
;
663 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
665 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
667 sa4
.sin_family
= AF_INET
;
668 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
669 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
);
671 sa4len
= sizeof( sa4
);
672 err
= getsockname( inMDNS
->p
->unicastSock4
, (struct sockaddr
*) &sa4
, &sa4len
);
673 require_noerr( err
, exit
);
674 inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
675 inMDNS
->p
->unicastSock4ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
676 err
= translate_errno( inMDNS
->p
->unicastSock4ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
677 require_noerr( err
, exit
);
678 err
= WSAEventSelect( inMDNS
->p
->unicastSock4
, inMDNS
->p
->unicastSock4ReadEvent
, FD_READ
);
679 require_noerr( err
, exit
);
680 #if( !TARGET_OS_WINDOWS_CE )
684 err
= WSAIoctl( inMDNS
->p
->unicastSock4
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
685 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock4RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock4RecvMsgPtr
), &size
, NULL
, NULL
);
689 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
696 // Set up the IPv6 unicast socket
698 inMDNS
->p
->unicastSock6
= INVALID_SOCKET
;
699 inMDNS
->p
->unicastSock6ReadEvent
= NULL
;
700 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
702 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
704 sa6
.sin6_family
= AF_INET6
;
705 sa6
.sin6_addr
= in6addr_any
;
706 sa6
.sin6_scope_id
= 0;
708 // This call will fail if the machine hasn't installed IPv6. In that case,
709 // the error will be WSAEAFNOSUPPORT.
711 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
);
712 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
713 inMDNS
->p
->unicastSock6ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
714 err
= translate_errno( inMDNS
->p
->unicastSock6ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
715 require_noerr( err
, exit
);
717 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
719 if ( inMDNS
->p
->unicastSock6
!= INVALID_SOCKET
)
721 sa6len
= sizeof( sa6
);
722 err
= getsockname( inMDNS
->p
->unicastSock6
, (struct sockaddr
*) &sa6
, &sa6len
);
723 require_noerr( err
, exit
);
724 inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
726 err
= WSAEventSelect( inMDNS
->p
->unicastSock6
, inMDNS
->p
->unicastSock6ReadEvent
, FD_READ
);
727 require_noerr( err
, exit
);
729 #if( !TARGET_OS_WINDOWS_CE )
733 err
= WSAIoctl( inMDNS
->p
->unicastSock6
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
734 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock6RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock6RecvMsgPtr
), &size
, NULL
, NULL
);
738 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
746 // Set up the mDNS thread.
748 err
= SetupSynchronizationObjects( inMDNS
);
749 require_noerr( err
, exit
);
751 err
= SetupThread( inMDNS
);
752 require_noerr( err
, exit
);
756 mDNSCoreInitComplete( inMDNS
, err
);
761 mDNSPlatformClose( inMDNS
);
763 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
767 //===========================================================================================================================
769 //===========================================================================================================================
771 void mDNSPlatformClose( mDNS
* const inMDNS
)
775 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
778 // Tear everything down in reverse order to how it was set up.
780 err
= TearDownThread( inMDNS
);
783 err
= TearDownInterfaceList( inMDNS
);
785 check( !inMDNS
->p
->inactiveInterfaceList
);
787 err
= TearDownRetryVPCCheck( inMDNS
);
790 err
= TearDownSynchronizationObjects( inMDNS
);
793 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
795 if ( inMDNS
->p
->unicastSock4ReadEvent
)
797 CloseHandle( inMDNS
->p
->unicastSock4ReadEvent
);
798 inMDNS
->p
->unicastSock4ReadEvent
= 0;
801 if ( IsValidSocket( inMDNS
->p
->unicastSock4
) )
803 close_compat( inMDNS
->p
->unicastSock4
);
808 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
810 if ( inMDNS
->p
->unicastSock6ReadEvent
)
812 CloseHandle( inMDNS
->p
->unicastSock6ReadEvent
);
813 inMDNS
->p
->unicastSock6ReadEvent
= 0;
816 if ( IsValidSocket( inMDNS
->p
->unicastSock6
) )
818 close_compat( inMDNS
->p
->unicastSock6
);
823 // Free the DLL needed for IPv6 support.
825 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
826 if( gIPHelperLibraryInstance
)
828 gGetAdaptersAddressesFunctionPtr
= NULL
;
830 FreeLibrary( gIPHelperLibraryInstance
);
831 gIPHelperLibraryInstance
= NULL
;
837 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
840 //===========================================================================================================================
841 // mDNSPlatformSendUDP
842 //===========================================================================================================================
846 const mDNS
* const inMDNS
,
847 const void * const inMsg
,
848 const mDNSu8
* const inMsgEnd
,
849 mDNSInterfaceID inInterfaceID
,
850 const mDNSAddr
* inDstIP
,
851 mDNSIPPort inDstPort
)
853 SOCKET sendingsocket
= INVALID_SOCKET
;
854 mStatus err
= mStatus_NoError
;
855 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
856 struct sockaddr_storage addr
;
859 DEBUG_USE_ONLY( inMDNS
);
861 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
867 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
869 if( inDstIP
->type
== mDNSAddrType_IPv4
)
871 struct sockaddr_in
* sa4
;
873 sa4
= (struct sockaddr_in
*) &addr
;
874 sa4
->sin_family
= AF_INET
;
875 sa4
->sin_port
= inDstPort
.NotAnInteger
;
876 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
877 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock4
;
879 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
881 struct sockaddr_in6
* sa6
;
883 sa6
= (struct sockaddr_in6
*) &addr
;
884 sa6
->sin6_family
= AF_INET6
;
885 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
886 sa6
->sin6_flowinfo
= 0;
887 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
888 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
889 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock6
;
893 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
894 err
= mStatus_BadParamErr
;
898 if (IsValidSocket(sendingsocket
))
900 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
901 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
905 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
907 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
909 err
= mStatus_TransientErr
;
913 require_noerr( err
, exit
);
922 //===========================================================================================================================
924 //===========================================================================================================================
926 void mDNSPlatformLock( const mDNS
* const inMDNS
)
930 if ( inMDNS
->p
->lockInitialized
)
932 EnterCriticalSection( &inMDNS
->p
->lock
);
936 //===========================================================================================================================
937 // mDNSPlatformUnlock
938 //===========================================================================================================================
940 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
945 if ( inMDNS
->p
->lockInitialized
)
947 check( inMDNS
->p
->threadID
);
949 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
950 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
952 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
956 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
957 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
959 LeaveCriticalSection( &inMDNS
->p
->lock
);
963 //===========================================================================================================================
964 // mDNSPlatformStrCopy
965 //===========================================================================================================================
967 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
972 strcpy( (char *) inDst
, (const char*) inSrc
);
975 //===========================================================================================================================
976 // mDNSPlatformStrLen
977 //===========================================================================================================================
979 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
983 return( (mDNSu32
) strlen( (const char *) inSrc
) );
986 //===========================================================================================================================
987 // mDNSPlatformMemCopy
988 //===========================================================================================================================
990 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
995 memcpy( inDst
, inSrc
, inSize
);
998 //===========================================================================================================================
999 // mDNSPlatformMemSame
1000 //===========================================================================================================================
1002 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
1007 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
1010 //===========================================================================================================================
1011 // mDNSPlatformMemZero
1012 //===========================================================================================================================
1014 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
1018 memset( inDst
, 0, inSize
);
1021 //===========================================================================================================================
1022 // mDNSPlatformMemAllocate
1023 //===========================================================================================================================
1025 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
1029 check( inSize
> 0 );
1031 mem
= malloc( inSize
);
1037 //===========================================================================================================================
1038 // mDNSPlatformMemFree
1039 //===========================================================================================================================
1041 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
1048 //===========================================================================================================================
1049 // mDNSPlatformRandomSeed
1050 //===========================================================================================================================
1052 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
1054 return( GetTickCount() );
1057 //===========================================================================================================================
1058 // mDNSPlatformTimeInit
1059 //===========================================================================================================================
1061 mDNSexport mStatus
mDNSPlatformTimeInit( void )
1063 // No special setup is required on Windows -- we just use GetTickCount().
1064 return( mStatus_NoError
);
1067 //===========================================================================================================================
1068 // mDNSPlatformRawTime
1069 //===========================================================================================================================
1071 mDNSs32
mDNSPlatformRawTime( void )
1073 return( (mDNSs32
) GetTickCount() );
1076 //===========================================================================================================================
1078 //===========================================================================================================================
1080 mDNSexport mDNSs32
mDNSPlatformUTC( void )
1082 return ( mDNSs32
) time( NULL
);
1085 //===========================================================================================================================
1086 // mDNSPlatformInterfaceNameToID
1087 //===========================================================================================================================
1089 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
1092 mDNSInterfaceData
* ifd
;
1098 // Search for an interface with the specified name,
1100 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1102 if( strcmp( ifd
->name
, inName
) == 0 )
1107 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1113 *outID
= (mDNSInterfaceID
) ifd
;
1115 err
= mStatus_NoError
;
1121 //===========================================================================================================================
1122 // mDNSPlatformInterfaceIDToInfo
1123 //===========================================================================================================================
1125 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
1128 mDNSInterfaceData
* ifd
;
1134 // Search for an interface with the specified ID,
1136 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1138 if( ifd
== (mDNSInterfaceData
*) inID
)
1143 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1147 outInfo
->name
= ifd
->name
;
1148 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
1149 err
= mStatus_NoError
;
1155 //===========================================================================================================================
1156 // mDNSPlatformInterfaceIDfromInterfaceIndex
1157 //===========================================================================================================================
1159 mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
* const inMDNS
, mDNSu32 inIndex
)
1164 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
1166 id
= mDNSInterface_LocalOnly
;
1168 else if( inIndex
!= 0 )
1170 mDNSInterfaceData
* ifd
;
1172 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1174 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
1176 id
= ifd
->interfaceInfo
.InterfaceID
;
1185 //===========================================================================================================================
1186 // mDNSPlatformInterfaceIndexfromInterfaceID
1187 //===========================================================================================================================
1189 mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
* const inMDNS
, mDNSInterfaceID inID
)
1194 if( inID
== mDNSInterface_LocalOnly
)
1196 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
1200 mDNSInterfaceData
* ifd
;
1202 // Search active interfaces.
1203 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1205 if( (mDNSInterfaceID
) ifd
== inID
)
1207 index
= ifd
->scopeID
;
1212 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
1216 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
1218 if( (mDNSInterfaceID
) ifd
== inID
)
1220 index
= ifd
->scopeID
;
1230 //===========================================================================================================================
1231 // mDNSPlatformTCPConnect
1232 //===========================================================================================================================
1235 mDNSPlatformTCPConnect(
1236 const mDNSAddr
* inDstIP
,
1237 mDNSOpaque16 inDstPort
,
1238 mDNSInterfaceID inInterfaceID
,
1239 TCPConnectionCallback inCallback
,
1243 u_long on
= 1; // "on" for setsockopt
1244 struct sockaddr_in saddr
;
1245 mDNSTCPConnectionData
* tcd
= NULL
;
1246 mStatus err
= mStatus_NoError
;
1248 DEBUG_UNUSED( inInterfaceID
);
1250 *outSock
= INVALID_SOCKET
;
1252 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1254 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1255 return mStatus_UnknownErr
;
1258 // Setup connection data object
1260 tcd
= (mDNSTCPConnectionData
*) malloc( sizeof( mDNSTCPConnectionData
) );
1261 require_action( tcd
, exit
, err
= mStatus_NoMemoryErr
);
1262 memset( tcd
, 0, sizeof( mDNSTCPConnectionData
) );
1264 tcd
->sock
= INVALID_SOCKET
;
1265 tcd
->callback
= inCallback
;
1266 tcd
->context
= inContext
;
1268 bzero(&saddr
, sizeof(saddr
));
1269 saddr
.sin_family
= AF_INET
;
1270 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1271 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1273 // Create the socket
1275 tcd
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
1276 err
= translate_errno( tcd
->sock
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
1277 require_noerr( err
, exit
);
1279 // Set it to be non-blocking
1281 err
= ioctlsocket( tcd
->sock
, FIONBIO
, &on
);
1282 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1283 require_noerr( err
, exit
);
1285 // Try and do connect
1287 err
= connect( tcd
->sock
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1288 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1289 tcd
->connected
= !err
? TRUE
: FALSE
;
1290 tcd
->pendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1291 err
= translate_errno( tcd
->pendingEvent
, GetLastError(), mStatus_UnknownErr
);
1292 require_noerr( err
, exit
);
1293 err
= WSAEventSelect( tcd
->sock
, tcd
->pendingEvent
, FD_CONNECT
|FD_READ
|FD_CLOSE
);
1294 require_noerr( err
, exit
);
1298 tcd
->next
= gTCPConnectionList
;
1299 gTCPConnectionList
= tcd
;
1301 gWaitListChanged
= TRUE
;
1303 *outSock
= (int) tcd
->sock
;
1309 err
= tcd
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1313 FreeTCPConnectionData( tcd
);
1319 //===========================================================================================================================
1320 // mDNSPlatformTCPCloseConnection
1321 //===========================================================================================================================
1323 void mDNSPlatformTCPCloseConnection( int inSock
)
1325 mDNSTCPConnectionData
* tcd
= gTCPConnectionList
;
1326 mDNSTCPConnectionData
* last
= NULL
;
1330 if ( tcd
->sock
== ( SOCKET
) inSock
)
1334 gTCPConnectionList
= tcd
->next
;
1338 last
->next
= tcd
->next
;
1341 FreeTCPConnectionData( tcd
);
1344 gWaitListChanged
= TRUE
;
1354 //===========================================================================================================================
1355 // mDNSPlatformReadTCP
1356 //===========================================================================================================================
1358 int mDNSPlatformReadTCP( int inSock
, void *inBuffer
, int inBufferSize
)
1363 nread
= recv( inSock
, inBuffer
, inBufferSize
, 0);
1364 err
= translate_errno( ( nread
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1365 require_noerr( err
, exit
);
1377 //===========================================================================================================================
1378 // mDNSPlatformWriteTCP
1379 //===========================================================================================================================
1381 int mDNSPlatformWriteTCP( int inSock
, const char *inMsg
, int inMsgSize
)
1386 nsent
= send( inSock
, inMsg
, inMsgSize
, 0 );
1388 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1389 require_noerr( err
, exit
);
1401 //===========================================================================================================================
1402 // dDNSPlatformGetConfig
1403 //===========================================================================================================================
1406 dDNSPlatformGetConfig(domainname
* const fqdn
, domainname
*const regDomain
, DNameListElem
** browseDomains
)
1409 char subKeyName
[kRegistryMaxKeyLength
+ 1];
1423 fqdn
->c
[0] = regDomain
->c
[0] = '\0';
1425 *browseDomains
= NULL
;
1427 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
1428 require_noerr( err
, exit
);
1430 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1431 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1433 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
1435 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
1451 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
, &key
);
1452 require_noerr( err
, exit
);
1454 // Get information about this node
1456 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
1457 require_noerr( err
, exit
);
1459 for ( i
= 0; i
< cSubKeys
; i
++)
1463 dwSize
= kRegistryMaxKeyLength
;
1465 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1469 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
1470 require_noerr( err
, exit
);
1472 dwSize
= sizeof( DWORD
);
1473 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
1475 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
1477 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
1479 dlog( kDebugLevelError
, "bad DDNS browse domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
1483 DNameListElem
* browseDomain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1484 require_action( browseDomain
, exit
, err
= mStatus_NoMemoryErr
);
1486 AssignDomainName(&browseDomain
->name
, &dname
);
1487 browseDomain
->next
= *browseDomains
;
1489 *browseDomains
= browseDomain
;
1493 RegCloseKey( subKey
);
1504 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
, &key
);
1505 require_noerr( err
, exit
);
1507 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1508 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1510 if ( !MakeDomainNameFromDNSNameString( regDomain
, name
) || !regDomain
->c
[0] )
1512 dlog( kDebugLevelError
, "bad DDNS registration domain in registry: %s", name
[0] ? name
: "(unknown)");
1520 RegCloseKey( subKey
);
1535 //===========================================================================================================================
1536 // dDNSPlatformSetNameStatus
1537 //===========================================================================================================================
1540 dDNSPlatformSetNameStatus(domainname
*const dname
, mStatus status
)
1542 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1548 ConvertDomainNameToCString(dname
, uname
);
1554 *p
= (char) tolower(*p
);
1555 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1559 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1560 name
= kServiceParametersNode
TEXT("\\DynDNS\\State\\HostNames");
1561 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1562 require_noerr( err
, exit
);
1564 status
= ( status
) ? 0 : 1;
1565 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &status
, sizeof(DWORD
) );
1566 require_noerr( err
, exit
);
1579 //===========================================================================================================================
1580 // dDNSPlatformSetSecretForDomain
1581 //===========================================================================================================================
1584 dDNSPlatformSetSecretForDomain( mDNS
*m
, const domainname
* inDomain
)
1591 LSA_OBJECT_ATTRIBUTES attrs
;
1592 LSA_HANDLE handle
= NULL
;
1596 // Initialize PolyStrings
1598 domain
.m_lsa
= NULL
;
1600 secret
.m_lsa
= NULL
;
1602 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
1604 ConvertDomainNameToCString( inDomain
, domain
.m_utf8
);
1605 dlen
= strlen( domain
.m_utf8
);
1606 for ( i
= 0; i
< dlen
; i
++ )
1608 domain
.m_utf8
[i
] = (char) tolower( domain
.m_utf8
[i
] ); // canonicalize -> lower case
1611 MakeDomainNameFromDNSNameString( &domain
.m_dname
, domain
.m_utf8
);
1613 // attrs are reserved, so initialize to zeroes.
1615 ZeroMemory( &attrs
, sizeof( attrs
) );
1617 // Get a handle to the Policy object on the local system
1619 res
= LsaOpenPolicy( NULL
, &attrs
, POLICY_GET_PRIVATE_INFORMATION
, &handle
);
1620 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1621 require_noerr( err
, exit
);
1623 // Get the encrypted data
1625 domain
.m_lsa
= ( PLSA_UNICODE_STRING
) malloc( sizeof( LSA_UNICODE_STRING
) );
1626 require_action( domain
.m_lsa
!= NULL
, exit
, err
= mStatus_NoMemoryErr
);
1627 err
= MakeLsaStringFromUTF8String( domain
.m_lsa
, domain
.m_utf8
);
1628 require_noerr( err
, exit
);
1632 res
= LsaRetrievePrivateData( handle
, domain
.m_lsa
, &key
.m_lsa
);
1633 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1634 require_noerr_quiet( err
, exit
);
1636 // <rdar://problem/4192119> Lsa secrets use a flat naming space. Therefore, we will prepend "$" to the keyname to
1637 // make sure it doesn't conflict with a zone name.
1639 // Convert the key to a domainname. Strip off the "$" prefix.
1641 err
= MakeUTF8StringFromLsaString( key
.m_utf8
, sizeof( key
.m_utf8
), key
.m_lsa
);
1642 require_noerr( err
, exit
);
1643 require_action( key
.m_utf8
[0] == '$', exit
, err
= kUnknownErr
);
1644 MakeDomainNameFromDNSNameString( &key
.m_dname
, key
.m_utf8
+ 1 );
1646 // Retrieve the secret
1648 res
= LsaRetrievePrivateData( handle
, key
.m_lsa
, &secret
.m_lsa
);
1649 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1650 require_noerr_quiet( err
, exit
);
1652 // Convert the secret to UTF8 string
1654 err
= MakeUTF8StringFromLsaString( secret
.m_utf8
, sizeof( secret
.m_utf8
), secret
.m_lsa
);
1655 require_noerr( err
, exit
);
1657 // And finally, tell the core about this secret
1659 debugf("Setting shared secret for zone %s with key %##s", domain
.m_utf8
, key
.m_dname
.c
);
1660 mDNS_SetSecretForZone( m
, &domain
.m_dname
, &key
.m_dname
, secret
.m_utf8
);
1664 if ( domain
.m_lsa
!= NULL
)
1666 if ( domain
.m_lsa
->Buffer
!= NULL
)
1668 free( domain
.m_lsa
->Buffer
);
1671 free( domain
.m_lsa
);
1674 if ( key
.m_lsa
!= NULL
)
1676 LsaFreeMemory( key
.m_lsa
);
1679 if ( secret
.m_lsa
!= NULL
)
1681 LsaFreeMemory( secret
.m_lsa
);
1692 //===========================================================================================================================
1693 // dDNSPlatformGetSearchDomainList
1694 //===========================================================================================================================
1697 dDNSPlatformGetSearchDomainList( void )
1699 char * searchList
= NULL
;
1700 DWORD searchListLen
;
1701 DNameListElem
* head
= NULL
;
1702 DNameListElem
* current
= NULL
;
1707 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1708 require_noerr( err
, exit
);
1710 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1711 require_noerr( err
, exit
);
1713 // Windows separates the search domains with ','
1715 tok
= strtok( searchList
, "," );
1718 if ( ( strcmp( tok
, "" ) != 0 ) && ( strcmp( tok
, "." ) != 0 ) )
1722 if ( MakeDomainNameFromDNSNameString( &domain
, tok
) )
1724 DNameListElem
* last
= current
;
1726 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1727 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1729 AssignDomainName( ¤t
->name
, &domain
);
1730 current
->next
= NULL
;
1739 last
->next
= current
;
1744 tok
= strtok( NULL
, "," );
1763 //===========================================================================================================================
1764 // dDNSPlatformGetReverseMapSearchDomainList
1765 //===========================================================================================================================
1768 dDNSPlatformGetReverseMapSearchDomainList( void )
1770 DNameListElem
* head
= NULL
;
1771 DNameListElem
* current
= NULL
;
1772 struct ifaddrs
* ifa
;
1775 ifa
= myGetIfAddrs( 1 );
1780 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !dDNS_SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1786 if (!dDNS_SetupAddr(&netmask
, ifa
->ifa_netmask
))
1788 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1789 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1790 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1791 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1793 if ( MakeDomainNameFromDNSNameString( &domain
, buffer
) )
1795 DNameListElem
* last
= current
;
1797 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1798 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1800 AssignDomainName( ¤t
->name
, &domain
);
1801 current
->next
= NULL
;
1810 last
->next
= current
;
1816 ifa
= ifa
->ifa_next
;
1825 //===========================================================================================================================
1826 // dDNSPlatformGetDNSServers
1827 //===========================================================================================================================
1830 dDNSPlatformGetDNSServers( void )
1832 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1833 FIXED_INFO
* fixedInfo
= NULL
;
1835 IP_ADDR_STRING
* dnsServerList
;
1836 IP_ADDR_STRING
* ipAddr
;
1837 IPAddrListElem
* head
= NULL
;
1838 IPAddrListElem
* current
= NULL
;
1841 mStatus err
= kUnknownErr
;
1843 // Get the primary interface.
1845 index
= GetPrimaryInterface();
1847 // This should have the interface index of the primary index. Fall back in cases where
1848 // it can't be determined.
1854 for ( i
= 0; i
< 100; i
++ )
1856 err
= GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
);
1858 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1863 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1864 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1867 require_noerr( err
, exit
);
1869 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1873 bufLen
= sizeof( FIXED_INFO
);
1875 for ( i
= 0; i
< 100; i
++ )
1879 GlobalFree( fixedInfo
);
1883 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1884 require_action( fixedInfo
, exit
, err
= mStatus_NoMemoryErr
);
1886 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1888 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1894 require_noerr( err
, exit
);
1896 dnsServerList
= &fixedInfo
->DnsServerList
;
1899 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1902 IPAddrListElem
* last
= current
;
1904 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1911 current
= (IPAddrListElem
*) malloc( sizeof( IPAddrListElem
) );
1912 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1914 memcpy( ¤t
->addr
, &addr
, sizeof( mDNSAddr
) );
1915 current
->next
= NULL
;
1924 last
->next
= current
;
1932 free( pAdapterInfo
);
1937 GlobalFree( fixedInfo
);
1944 //===========================================================================================================================
1945 // dDNSPlatformGetDomainName
1946 //===========================================================================================================================
1949 dDNSPlatformGetDomainName( void )
1951 DNameListElem
* head
= NULL
;
1953 IP_ADAPTER_INFO
* pAdapterInfo
;
1954 IP_ADAPTER_INFO
* pAdapter
;
1958 LPSTR domain
= NULL
;
1961 mStatus err
= mStatus_NoError
;
1963 pAdapterInfo
= NULL
;
1965 for ( i
= 0; i
< 100; i
++ )
1967 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1969 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1974 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
1975 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1978 require_noerr( err
, exit
);
1980 index
= GetPrimaryInterface();
1982 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1984 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1985 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1986 pAdapter
->GatewayList
.IpAddress
.String
&&
1987 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1988 ( !index
|| ( pAdapter
->Index
== index
) ) )
1990 // Found one that will work
1994 _snprintf( keyName
, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter
->AdapterName
);
1996 err
= RegCreateKeyA( HKEY_LOCAL_MACHINE
, keyName
, &key
);
1997 require_noerr( err
, exit
);
1999 err
= RegQueryString( key
, "Domain", &domain
, &dwSize
, NULL
);
2002 if ( !domain
|| !domain
[0] )
2010 err
= RegQueryString( key
, "DhcpDomain", &domain
, &dwSize
, NULL
);
2014 if ( domain
&& domain
[0] && ( MakeDomainNameFromDNSNameString( &dname
, domain
) || !dname
.c
[0] ) )
2016 head
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
2017 require_action( head
, exit
, err
= mStatus_NoMemoryErr
);
2019 AssignDomainName( &head
->name
, &dname
);
2031 free( pAdapterInfo
);
2048 //===========================================================================================================================
2049 // dDNSPlatformRegisterSplitDNS
2050 //===========================================================================================================================
2053 dDNSPlatformRegisterSplitDNS( mDNS
* m
)
2057 return mStatus_UnsupportedErr
;
2061 //===========================================================================================================================
2062 // dDNSPlatformGetPrimaryInterface
2063 //===========================================================================================================================
2066 dDNSPlatformGetPrimaryInterface( mDNS
* m
, mDNSAddr
* primary
, mDNSAddr
* router
)
2068 IP_ADAPTER_INFO
* pAdapterInfo
;
2069 IP_ADAPTER_INFO
* pAdapter
;
2074 mStatus err
= mStatus_NoError
;
2078 pAdapterInfo
= NULL
;
2082 for ( i
= 0; i
< 100; i
++ )
2084 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2086 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2091 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2092 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2095 require_noerr( err
, exit
);
2097 index
= GetPrimaryInterface();
2099 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2101 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2102 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2103 pAdapter
->GatewayList
.IpAddress
.String
&&
2104 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2105 ( StringToAddress( primary
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
2106 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
2107 ( !index
|| ( pAdapter
->Index
== index
) ) )
2109 // Found one that will work
2120 free( pAdapterInfo
);
2127 //===========================================================================================================================
2128 // dDNSPlatformDefaultBrowseDomainChanged
2129 //===========================================================================================================================
2132 dDNSPlatformDefaultBrowseDomainChanged( const domainname
*d
, mDNSBool add
)
2135 DEBUG_UNUSED( add
);
2137 // This is a no-op on Windows
2141 //===========================================================================================================================
2142 // dDNSPlatformDefaultRegDomainChanged
2143 //===========================================================================================================================
2146 dDNSPlatformDefaultRegDomainChanged( const domainname
* d
, mDNSBool add
)
2149 DEBUG_UNUSED( add
);
2151 // This is a no-op on Windows
2159 //===========================================================================================================================
2161 //===========================================================================================================================
2163 #if( MDNS_DEBUGMSGS )
2164 void debugf_( const char *inFormat
, ... )
2170 va_start( args
, inFormat
);
2171 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2174 dlog( kDebugLevelInfo
, "%s\n", buffer
);
2178 //===========================================================================================================================
2180 //===========================================================================================================================
2182 #if( MDNS_DEBUGMSGS > 1 )
2183 void verbosedebugf_( const char *inFormat
, ... )
2189 va_start( args
, inFormat
);
2190 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2193 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
2197 //===========================================================================================================================
2199 //===========================================================================================================================
2202 void LogMsg( const char *inFormat, ... )
2208 va_start( args, inFormat );
2209 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2212 dlog( kDebugLevelWarning, "%s\n", buffer );
2218 #pragma mark == Platform Internals ==
2221 //===========================================================================================================================
2222 // SetupSynchronizationObjects
2223 //===========================================================================================================================
2225 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
2229 InitializeCriticalSection( &inMDNS
->p
->lock
);
2230 inMDNS
->p
->lockInitialized
= mDNStrue
;
2232 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2233 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2234 require_noerr( err
, exit
);
2236 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2237 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2238 require_noerr( err
, exit
);
2240 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2241 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2242 require_noerr( err
, exit
);
2244 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2245 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2246 require_noerr( err
, exit
);
2251 TearDownSynchronizationObjects( inMDNS
);
2256 //===========================================================================================================================
2257 // TearDownSynchronizationObjects
2258 //===========================================================================================================================
2260 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
2262 if( inMDNS
->p
->quitEvent
)
2264 CloseHandle( inMDNS
->p
->quitEvent
);
2265 inMDNS
->p
->quitEvent
= 0;
2267 if( inMDNS
->p
->cancelEvent
)
2269 CloseHandle( inMDNS
->p
->cancelEvent
);
2270 inMDNS
->p
->cancelEvent
= 0;
2272 if( inMDNS
->p
->interfaceListChangedEvent
)
2274 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
2275 inMDNS
->p
->interfaceListChangedEvent
= 0;
2277 if( inMDNS
->p
->wakeupEvent
)
2279 CloseHandle( inMDNS
->p
->wakeupEvent
);
2280 inMDNS
->p
->wakeupEvent
= 0;
2282 if( inMDNS
->p
->lockInitialized
)
2284 DeleteCriticalSection( &inMDNS
->p
->lock
);
2285 inMDNS
->p
->lockInitialized
= mDNSfalse
;
2287 return( mStatus_NoError
);
2291 //===========================================================================================================================
2293 //===========================================================================================================================
2295 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
)
2298 char tempString
[ 256 ];
2303 // Set up the nice name.
2304 tempString
[ 0 ] = '\0';
2307 // First try and open the registry key that contains the computer description value
2308 if (inMDNS
->p
->descKey
== NULL
)
2310 LPCTSTR s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2311 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &inMDNS
->p
->descKey
);
2312 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2316 inMDNS
->p
->descKey
= NULL
;
2320 // if we opened it...
2321 if (inMDNS
->p
->descKey
!= NULL
)
2324 DWORD descSize
= sizeof( desc
);
2326 // look for the computer description
2327 err
= RegQueryValueEx(inMDNS
->p
->descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2331 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2340 // if we can't find it in the registry, then use the hostname of the machine
2341 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2343 DWORD tempStringLen
= sizeof( tempString
);
2346 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2347 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2352 err
= WindowsLatin1toUTF8( tempString
, utf8
, sizeof( utf8
) );
2361 // if we can't get the hostname
2362 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2364 // Invalidate name so fall back to a default name.
2366 strcpy( utf8
, kMDNSDefaultName
);
2369 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2370 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2371 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2373 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2379 //===========================================================================================================================
2381 //===========================================================================================================================
2383 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2386 char tempString
[ 256 ];
2387 DWORD tempStringLen
;
2388 domainlabel tempLabel
;
2393 // Set up the nice name.
2394 tempString
[ 0 ] = '\0';
2396 // use the hostname of the machine
2397 tempStringLen
= sizeof( tempString
);
2398 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2399 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2402 // if we can't get the hostname
2403 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2405 // Invalidate name so fall back to a default name.
2407 strcpy( tempString
, kMDNSDefaultName
);
2410 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2411 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2412 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2414 // Set up the host name.
2416 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2417 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2419 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2421 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2424 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2426 mDNS_SetFQDN( inMDNS
);
2428 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2433 //===========================================================================================================================
2435 //===========================================================================================================================
2437 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2443 err
= SetupNiceName( inMDNS
);
2446 err
= SetupHostName( inMDNS
);
2453 //===========================================================================================================================
2454 // SetupInterfaceList
2455 //===========================================================================================================================
2457 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2460 mDNSInterfaceData
** next
;
2461 mDNSInterfaceData
* ifd
;
2462 struct ifaddrs
* addrs
;
2464 struct ifaddrs
* loopbackv4
;
2465 struct ifaddrs
* loopbackv6
;
2470 mDNSBool foundUnicastSock4DestAddr
;
2471 mDNSBool foundUnicastSock6DestAddr
;
2473 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2477 inMDNS
->p
->registeredLoopback4
= mDNSfalse
;
2479 foundv4
= mDNSfalse
;
2480 foundv6
= mDNSfalse
;
2481 foundUnicastSock4DestAddr
= mDNSfalse
;
2482 foundUnicastSock6DestAddr
= mDNSfalse
;
2484 // Tear down any existing interfaces that may be set up.
2486 TearDownInterfaceList( inMDNS
);
2488 // Set up the name of this machine.
2490 err
= SetupName( inMDNS
);
2493 // Set up the interface list change notification.
2495 err
= SetupNotifications( inMDNS
);
2498 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2499 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2501 err
= getifaddrs( &addrs
);
2502 require_noerr( err
, exit
);
2506 next
= &inMDNS
->p
->interfaceList
;
2508 flagMask
= IFF_UP
| IFF_MULTICAST
;
2509 flagTest
= IFF_UP
| IFF_MULTICAST
;
2511 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2512 for( p
= addrs
; p
; p
= p
->ifa_next
)
2514 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2518 if( p
->ifa_flags
& IFF_LOOPBACK
)
2526 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2527 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2529 err
= SetupInterface( inMDNS
, p
, &ifd
);
2530 require_noerr( err
, exit
);
2532 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2533 // register him, but we also want to note that we haven't found a v4 interface
2534 // so that we register loopback so same host operations work
2536 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2541 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2542 // of determing the destination address of a packet that is sent to us.
2543 // For multicast packets, that's easy to determine. But for the unicast
2544 // sockets, we'll fake it by taking the address of the first interface
2545 // that is successfully setup.
2547 if ( !foundUnicastSock4DestAddr
)
2549 inMDNS
->p
->unicastSock4DestAddr
= ifd
->interfaceInfo
.ip
;
2550 foundUnicastSock4DestAddr
= TRUE
;
2555 ++inMDNS
->p
->interfaceCount
;
2559 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2561 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2562 for( p
= addrs
; p
; p
= p
->ifa_next
)
2564 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2568 if( p
->ifa_flags
& IFF_LOOPBACK
)
2576 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2577 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2579 err
= SetupInterface( inMDNS
, p
, &ifd
);
2580 require_noerr( err
, exit
);
2582 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2583 // register him, but we also want to note that we haven't found a v4 interface
2584 // so that we register loopback so same host operations work
2586 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2591 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2592 // of determing the destination address of a packet that is sent to us.
2593 // For multicast packets, that's easy to determine. But for the unicast
2594 // sockets, we'll fake it by taking the address of the first interface
2595 // that is successfully setup.
2597 if ( !foundUnicastSock6DestAddr
)
2599 inMDNS
->p
->unicastSock6DestAddr
= ifd
->interfaceInfo
.ip
;
2600 foundUnicastSock6DestAddr
= TRUE
;
2605 ++inMDNS
->p
->interfaceCount
;
2609 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2611 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2613 flagMask
|= IFF_LOOPBACK
;
2614 flagTest
|= IFF_LOOPBACK
;
2616 for( p
= addrs
; p
; p
= p
->ifa_next
)
2618 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2622 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2633 if ( !foundv4
&& loopbackv4
)
2635 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2636 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2638 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2639 require_noerr( err
, exit
);
2641 inMDNS
->p
->registeredLoopback4
= mDNStrue
;
2643 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2645 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2646 // of determing the destination address of a packet that is sent to us.
2647 // For multicast packets, that's easy to determine. But for the unicast
2648 // sockets, we'll fake it by taking the address of the first interface
2649 // that is successfully setup.
2651 if ( !foundUnicastSock4DestAddr
)
2653 inMDNS
->p
->unicastSock4DestAddr
= ifd
->defaultAddr
;
2654 foundUnicastSock4DestAddr
= TRUE
;
2660 ++inMDNS
->p
->interfaceCount
;
2666 TearDownInterfaceList( inMDNS
);
2670 freeifaddrs( addrs
);
2672 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2676 //===========================================================================================================================
2677 // TearDownInterfaceList
2678 //===========================================================================================================================
2680 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2683 mDNSInterfaceData
** p
;
2684 mDNSInterfaceData
* ifd
;
2686 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2690 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2691 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2692 // so that remove events that occur after an interface goes away can still report the correct interface.
2694 p
= &inMDNS
->p
->inactiveInterfaceList
;
2698 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2704 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2709 // Tear down interface list change notifications.
2711 err
= TearDownNotifications( inMDNS
);
2714 // Tear down all the interfaces.
2716 while( inMDNS
->p
->interfaceList
)
2718 ifd
= inMDNS
->p
->interfaceList
;
2719 inMDNS
->p
->interfaceList
= ifd
->next
;
2721 TearDownInterface( inMDNS
, ifd
);
2723 inMDNS
->p
->interfaceCount
= 0;
2725 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2726 return( mStatus_NoError
);
2729 //===========================================================================================================================
2731 //===========================================================================================================================
2733 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2735 mDNSInterfaceData
* ifd
;
2736 mDNSInterfaceData
* p
;
2741 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2745 check( inIFA
->ifa_addr
);
2748 // Allocate memory for the interface and initialize it.
2750 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2751 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2752 ifd
->sock
= kInvalidSocketRef
;
2753 ifd
->index
= inIFA
->ifa_extra
.index
;
2754 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2755 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2756 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2757 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2759 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2760 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2762 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2763 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2764 // on a large configured network, which means there's a good chance that most or all the other devices on that
2765 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2766 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2767 // devices on a large configured network, so we are willing to make that sacrifice.
2769 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2770 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2772 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2774 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2776 if (!ifd
->interfaceInfo
.InterfaceID
)
2778 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2781 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2782 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2783 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2785 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2792 if ( !ifd
->interfaceInfo
.InterfaceID
)
2794 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2797 // Set up a socket for this interface (if needed).
2799 if( ifd
->interfaceInfo
.McastTxRx
)
2801 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &sock
);
2802 require_noerr( err
, exit
);
2804 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2806 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2808 #if( !TARGET_OS_WINDOWS_CE )
2812 // If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
2813 // a bug in VPC itself.
2815 err
= inMDNS
->p
->inVirtualPC
;
2819 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
2820 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
2825 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
2830 // Set up the read pending event and associate it so we can block until data is available for this socket.
2832 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2833 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2834 require_noerr( err
, exit
);
2836 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
2837 require_noerr( err
, exit
);
2841 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2843 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2844 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2845 require_noerr( err
, exit
);
2848 // Register this interface with mDNS.
2850 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2851 require_noerr( err
, exit
);
2853 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2854 require_noerr( err
, exit
);
2856 ifd
->interfaceInfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
2858 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, mDNSfalse
);
2859 require_noerr( err
, exit
);
2860 ifd
->hostRegistered
= mDNStrue
;
2862 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2872 TearDownInterface( inMDNS
, ifd
);
2874 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2878 //===========================================================================================================================
2879 // TearDownInterface
2880 //===========================================================================================================================
2882 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2889 // Deregister this interface with mDNS.
2891 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2893 if( inIFD
->hostRegistered
)
2895 inIFD
->hostRegistered
= mDNSfalse
;
2896 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
, mDNSfalse
);
2899 // Tear down the multicast socket.
2901 if( inIFD
->readPendingEvent
)
2903 CloseHandle( inIFD
->readPendingEvent
);
2904 inIFD
->readPendingEvent
= 0;
2908 inIFD
->sock
= kInvalidSocketRef
;
2909 if( IsValidSocket( sock
) )
2911 close_compat( sock
);
2914 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2915 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2917 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2919 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2920 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2921 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2925 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2928 return( mStatus_NoError
);
2931 //===========================================================================================================================
2933 //===========================================================================================================================
2935 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2941 DEBUG_UNUSED( inMDNS
);
2943 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2945 check( outSocketRef
);
2947 // Set up an IPv4 or IPv6 UDP socket.
2949 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2950 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2951 require_noerr( err
, exit
);
2953 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2954 // if we're creating a multicast socket
2956 if ( port
.NotAnInteger
)
2959 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2960 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2963 if( inAddr
->sa_family
== AF_INET
)
2966 struct sockaddr_in sa4
;
2967 struct ip_mreq mreqv4
;
2969 // Bind the socket to the desired port
2971 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2972 memset( &sa4
, 0, sizeof( sa4
) );
2973 sa4
.sin_family
= AF_INET
;
2974 sa4
.sin_port
= port
.NotAnInteger
;
2975 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2977 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2978 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2980 // Turn on option to receive destination addresses and receiving interface.
2983 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2984 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2986 if (port
.NotAnInteger
)
2988 // Join the all-DNS multicast group so we receive Multicast DNS packets
2990 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
2991 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
2992 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
2993 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2995 // Specify the interface to send multicast packets on this socket.
2997 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2998 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
2999 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3001 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3004 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3005 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3008 // Send unicast packets with TTL 255 (helps against spoofing).
3011 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
3012 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3014 // Send multicast packets with TTL 255 (helps against spoofing).
3017 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
3018 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3021 else if( inAddr
->sa_family
== AF_INET6
)
3023 struct sockaddr_in6
* sa6p
;
3024 struct sockaddr_in6 sa6
;
3025 struct ipv6_mreq mreqv6
;
3027 sa6p
= (struct sockaddr_in6
*) inAddr
;
3029 // Bind the socket to the desired port
3031 memset( &sa6
, 0, sizeof( sa6
) );
3032 sa6
.sin6_family
= AF_INET6
;
3033 sa6
.sin6_port
= port
.NotAnInteger
;
3034 sa6
.sin6_flowinfo
= 0;
3035 sa6
.sin6_addr
= sa6p
->sin6_addr
;
3036 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
3038 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
3039 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
3041 // Turn on option to receive destination addresses and receiving interface.
3044 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
3045 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3047 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
3048 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
3049 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
3051 #if( defined( IPV6_V6ONLY ) )
3053 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
3054 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3057 if ( port
.NotAnInteger
)
3059 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3061 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroupv6
);
3062 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
3063 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
3064 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3066 // Specify the interface to send multicast packets on this socket.
3068 option
= (int) sa6p
->sin6_scope_id
;
3069 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
3070 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3072 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3075 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3076 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3079 // Send unicast packets with TTL 255 (helps against spoofing).
3082 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
3083 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3085 // Send multicast packets with TTL 255 (helps against spoofing).
3088 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
3089 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3093 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
3094 err
= kUnsupportedErr
;
3100 *outSocketRef
= sock
;
3101 sock
= kInvalidSocketRef
;
3102 err
= mStatus_NoError
;
3105 if( IsValidSocket( sock
) )
3107 close_compat( sock
);
3112 //===========================================================================================================================
3114 //===========================================================================================================================
3116 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
3123 if( inSA
->sa_family
== AF_INET
)
3125 struct sockaddr_in
* sa4
;
3127 sa4
= (struct sockaddr_in
*) inSA
;
3128 outIP
->type
= mDNSAddrType_IPv4
;
3129 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
3132 outPort
->NotAnInteger
= sa4
->sin_port
;
3134 err
= mStatus_NoError
;
3136 else if( inSA
->sa_family
== AF_INET6
)
3138 struct sockaddr_in6
* sa6
;
3140 sa6
= (struct sockaddr_in6
*) inSA
;
3141 outIP
->type
= mDNSAddrType_IPv6
;
3142 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
3143 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
3145 outIP
->ip
.v6
.w
[ 1 ] = 0;
3149 outPort
->NotAnInteger
= sa6
->sin6_port
;
3151 err
= mStatus_NoError
;
3155 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
3156 err
= mStatus_BadParamErr
;
3161 //===========================================================================================================================
3162 // SetupNotifications
3163 //===========================================================================================================================
3165 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
3169 unsigned long param
;
3174 // Register to listen for address list changes.
3176 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3177 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
3178 require_noerr( err
, exit
);
3179 inMDNS
->p
->interfaceListChangedSocket
= sock
;
3181 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
3182 // when a change to the interface list is detected.
3185 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
3186 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3187 require_noerr( err
, exit
);
3191 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
3194 check( errno_compat() == WSAEWOULDBLOCK
);
3197 err
= WSAEventSelect( sock
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
3198 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3199 require_noerr( err
, exit
);
3201 inMDNS
->p
->descChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
3202 err
= translate_errno( inMDNS
->p
->descChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3203 require_noerr( err
, exit
);
3205 if (inMDNS
->p
->descKey
!= NULL
)
3207 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3208 require_noerr( err
, exit
);
3211 // This will catch all changes to tcp/ip networking, including changes to the domain search list
3213 inMDNS
->p
->tcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3214 err
= translate_errno( inMDNS
->p
->tcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3215 require_noerr( err
, exit
);
3217 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS
->p
->tcpipKey
);
3218 require_noerr( err
, exit
);
3220 err
= RegNotifyChangeKeyValue(inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3221 require_noerr( err
, exit
);
3223 // This will catch all changes to ddns configuration
3225 inMDNS
->p
->ddnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3226 err
= translate_errno( inMDNS
->p
->ddnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3227 require_noerr( err
, exit
);
3229 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &inMDNS
->p
->ddnsKey
);
3230 require_noerr( err
, exit
);
3232 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3233 require_noerr( err
, exit
);
3238 TearDownNotifications( inMDNS
);
3243 //===========================================================================================================================
3244 // TearDownNotifications
3245 //===========================================================================================================================
3247 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
3249 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
3251 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
3252 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
3255 if ( inMDNS
->p
->descChangedEvent
!= NULL
)
3257 CloseHandle( inMDNS
->p
->descChangedEvent
);
3258 inMDNS
->p
->descChangedEvent
= NULL
;
3261 if ( inMDNS
->p
->descKey
!= NULL
)
3263 RegCloseKey( inMDNS
->p
->descKey
);
3264 inMDNS
->p
->descKey
= NULL
;
3267 if ( inMDNS
->p
->tcpipChangedEvent
!= NULL
)
3269 CloseHandle( inMDNS
->p
->tcpipChangedEvent
);
3270 inMDNS
->p
->tcpipChangedEvent
= NULL
;
3273 if ( inMDNS
->p
->ddnsChangedEvent
!= NULL
)
3275 CloseHandle( inMDNS
->p
->ddnsChangedEvent
);
3276 inMDNS
->p
->ddnsChangedEvent
= NULL
;
3279 if ( inMDNS
->p
->ddnsKey
!= NULL
)
3281 RegCloseKey( inMDNS
->p
->ddnsKey
);
3282 inMDNS
->p
->ddnsKey
= NULL
;
3285 return( mStatus_NoError
);
3289 //===========================================================================================================================
3290 // SetupRetryVPCCheck
3291 //===========================================================================================================================
3294 SetupRetryVPCCheck( mDNS
* const inMDNS
)
3296 LARGE_INTEGER liDueTime
;
3300 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up retry VirtualPC check\n" );
3302 liDueTime
.QuadPart
= kRetryVPCRate
;
3304 // Create a waitable timer.
3306 inMDNS
->p
->vpcCheckEvent
= CreateWaitableTimer( NULL
, TRUE
, TEXT( "VPCCheckTimer" ) );
3307 err
= translate_errno( inMDNS
->p
->vpcCheckEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3308 require_noerr( err
, exit
);
3310 // Set a timer to wait for 10 seconds.
3312 ok
= SetWaitableTimer( inMDNS
->p
->vpcCheckEvent
, &liDueTime
, 0, NULL
, NULL
, 0 );
3313 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
3314 require_noerr( err
, exit
);
3316 inMDNS
->p
->timersCount
++;
3324 //===========================================================================================================================
3325 // TearDownRetryVPCCheck
3326 //===========================================================================================================================
3329 TearDownRetryVPCCheck( mDNS
* const inMDNS
)
3331 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down retry VirtualPC check\n" );
3333 if ( inMDNS
->p
->vpcCheckEvent
)
3335 CancelWaitableTimer( inMDNS
->p
->vpcCheckEvent
);
3336 CloseHandle( inMDNS
->p
->vpcCheckEvent
);
3338 inMDNS
->p
->vpcCheckEvent
= NULL
;
3339 inMDNS
->p
->timersCount
--;
3342 return ( mStatus_NoError
);
3350 //===========================================================================================================================
3352 //===========================================================================================================================
3354 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
3357 HANDLE threadHandle
;
3361 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
3363 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3364 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3366 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3367 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3368 require_noerr( err
, exit
);
3370 inMDNS
->p
->initStatus
= mStatus_Invalid
;
3372 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3373 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3375 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
3376 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
3377 require_noerr( err
, exit
);
3379 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
3380 err
= translate_errno( result
== WAIT_OBJECT_0
, (mStatus
) GetLastError(), kUnknownErr
);
3381 require_noerr( err
, exit
);
3382 err
= inMDNS
->p
->initStatus
;
3383 require_noerr( err
, exit
);
3386 if( inMDNS
->p
->initEvent
)
3388 CloseHandle( inMDNS
->p
->initEvent
);
3389 inMDNS
->p
->initEvent
= 0;
3391 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
3395 //===========================================================================================================================
3397 //===========================================================================================================================
3399 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
3401 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3402 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3404 if( inMDNS
->p
->cancelEvent
)
3409 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
3410 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3412 if( inMDNS
->p
->quitEvent
)
3414 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
3415 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
3418 return( mStatus_NoError
);
3421 //===========================================================================================================================
3423 //===========================================================================================================================
3425 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
3437 m
= (mDNS
*) inParam
;
3438 err
= ProcessingThreadInitialize( m
);
3444 // Set up the list of objects we'll be waiting on.
3448 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
3449 require_noerr( err
, exit
);
3451 // Main processing loop.
3453 gWaitListChanged
= FALSE
;
3457 // Give the mDNS core a chance to do its work and determine next event time.
3459 mDNSs32 interval
= mDNS_Execute(m
) - mDNS_TimeNow(m
);
3461 if ( gWaitListChanged
)
3466 if (m
->p
->idleThreadCallback
)
3468 interval
= m
->p
->idleThreadCallback(m
, interval
);
3470 if (interval
< 0) interval
= 0;
3471 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
3472 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
3474 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3476 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
3477 check( result
!= WAIT_FAILED
);
3479 if ( result
!= WAIT_FAILED
)
3481 if( result
== WAIT_TIMEOUT
)
3483 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3485 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
3488 else if( result
== kWaitListCancelEvent
)
3490 // Cancel event. Set the done flag and break to exit.
3492 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
3496 else if( result
== kWaitListInterfaceListChangedEvent
)
3498 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3500 ProcessingThreadInterfaceListChanged( m
);
3503 else if( result
== kWaitListWakeupEvent
)
3505 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3507 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
3510 else if ( result
== kWaitListComputerDescriptionEvent
)
3513 // The computer description might have changed
3515 ProcessingThreadComputerDescriptionChanged( m
);
3518 else if ( result
== kWaitListTCPIPEvent
)
3521 // The TCP/IP might have changed
3523 ProcessingThreadTCPIPConfigChanged( m
);
3526 else if ( result
== kWaitListDynDNSEvent
)
3529 // The DynDNS config might have changed
3531 ProcessingThreadDynDNSConfigChanged( m
);
3538 // Socket data available event. Determine which socket and process the packet.
3540 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
3541 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
3542 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
3543 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
3545 HANDLE signaledObject
;
3547 mDNSInterfaceData
* ifd
;
3548 mDNSTCPConnectionData
* tcd
;
3550 signaledObject
= waitList
[ waitItemIndex
];
3552 if ( m
->p
->vpcCheckEvent
== signaledObject
)
3554 ProcessingThreadRetryVPCCheck( m
);
3559 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3560 if ( m
->p
->unicastSock4ReadEvent
== signaledObject
)
3562 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock4
);
3567 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3568 if ( m
->p
->unicastSock6ReadEvent
== signaledObject
)
3570 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock6
);
3575 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3577 if( ifd
->readPendingEvent
== signaledObject
)
3579 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
3584 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3586 if ( tcd
->pendingEvent
== signaledObject
)
3588 mDNSBool connect
= FALSE
;
3590 if ( !tcd
->connected
)
3592 tcd
->connected
= mDNStrue
;
3596 tcd
->callback( ( int ) tcd
->sock
, tcd
->context
, connect
);
3608 // Unexpected wait result.
3610 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
3617 err
= ProcessingThreadInitialize( m
);
3623 // Release the wait list.
3633 // Signal the quit event to indicate that the thread is finished.
3636 wasSet
= SetEvent( m
->p
->quitEvent
);
3637 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3639 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3640 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3642 _endthreadex_compat( 0 );
3646 //===========================================================================================================================
3647 // ProcessingThreadInitialize
3648 //===========================================================================================================================
3650 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
3655 inMDNS
->p
->threadID
= GetCurrentThreadId();
3657 err
= IsVPCRunning( &inMDNS
->p
->inVirtualPC
);
3661 TearDownRetryVPCCheck( inMDNS
);
3662 SetupRetryVPCCheck( inMDNS
);
3665 err
= SetupInterfaceList( inMDNS
);
3666 require_noerr( err
, exit
);
3668 err
= dDNS_Setup( inMDNS
);
3669 require_noerr( err
, exit
);
3671 err
= dDNS_InitDNSConfig( inMDNS
);
3672 require_noerr( err
, exit
);
3678 TearDownInterfaceList( inMDNS
);
3679 TearDownRetryVPCCheck( inMDNS
);
3681 inMDNS
->p
->initStatus
= err
;
3683 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
3684 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3688 //===========================================================================================================================
3689 // ProcessingThreadSetupWaitList
3690 //===========================================================================================================================
3692 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
3697 HANDLE
* waitItemPtr
;
3698 mDNSInterfaceData
* ifd
;
3699 mDNSTCPConnectionData
* tcd
;
3701 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
3704 check( outWaitList
);
3705 check( outWaitListCount
);
3707 // Allocate an array to hold all the objects to wait on.
3709 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->timersCount
+ inMDNS
->p
->interfaceCount
+ gTCPConnections
;
3710 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
3711 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
3712 waitItemPtr
= waitList
;
3714 // Add the fixed wait items to the beginning of the list.
3716 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
3717 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
3718 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
3719 *waitItemPtr
++ = inMDNS
->p
->descChangedEvent
;
3720 *waitItemPtr
++ = inMDNS
->p
->tcpipChangedEvent
;
3721 *waitItemPtr
++ = inMDNS
->p
->ddnsChangedEvent
;
3725 if ( inMDNS
->p
->vpcCheckEvent
)
3727 *waitItemPtr
++ = inMDNS
->p
->vpcCheckEvent
;
3730 // Append all the dynamic wait items to the list.
3731 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3732 *waitItemPtr
++ = inMDNS
->p
->unicastSock4ReadEvent
;
3735 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3736 *waitItemPtr
++ = inMDNS
->p
->unicastSock6ReadEvent
;
3739 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3741 *waitItemPtr
++ = ifd
->readPendingEvent
;
3744 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3746 *waitItemPtr
++ = tcd
->pendingEvent
;
3749 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
3751 *outWaitList
= waitList
;
3752 *outWaitListCount
= waitListCount
;
3754 err
= mStatus_NoError
;
3761 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
3765 //===========================================================================================================================
3766 // ProcessingThreadProcessPacket
3767 //===========================================================================================================================
3769 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
)
3772 const mDNSInterfaceID iid
= inIFD
? inIFD
->interfaceInfo
.InterfaceID
: NULL
;
3773 LPFN_WSARECVMSG recvMsgPtr
;
3779 struct sockaddr_storage addr
;
3785 check( IsValidSocket( inSock
) );
3787 // Set up the default in case the packet info options are not supported or reported correctly.
3791 recvMsgPtr
= inIFD
->wsaRecvMsgFunctionPtr
;
3792 dstAddr
= inIFD
->defaultAddr
;
3793 dstPort
= MulticastDNSPort
;
3796 else if ( inSock
== inMDNS
->p
->unicastSock4
)
3798 recvMsgPtr
= inMDNS
->p
->unicastSock4RecvMsgPtr
;
3799 dstAddr
= inMDNS
->p
->unicastSock4DestAddr
;
3800 dstPort
= zeroIPPort
;
3803 else if ( inSock
== inMDNS
->p
->unicastSock6
)
3805 recvMsgPtr
= inMDNS
->p
->unicastSock6RecvMsgPtr
;
3806 dstAddr
= inMDNS
->p
->unicastSock6DestAddr
;
3807 dstPort
= zeroIPPort
;
3812 dlog( kDebugLevelError
, DEBUG_NAME
"packet received on unknown socket\n" );
3816 #if( !TARGET_OS_WINDOWS_CE )
3821 uint8_t controlBuffer
[ 128 ];
3823 LPWSACMSGHDR header
;
3825 // Set up the buffer and read the packet.
3827 msg
.name
= (LPSOCKADDR
) &addr
;
3828 msg
.namelen
= (INT
) sizeof( addr
);
3829 buf
.buf
= (char *) &packet
;
3830 buf
.len
= (u_long
) sizeof( packet
);
3831 msg
.lpBuffers
= &buf
;
3832 msg
.dwBufferCount
= 1;
3833 msg
.Control
.buf
= (char *) controlBuffer
;
3834 msg
.Control
.len
= (u_long
) sizeof( controlBuffer
);
3837 err
= recvMsgPtr( inSock
, &msg
, &size
, NULL
, NULL
);
3838 err
= translate_errno( err
== 0, (OSStatus
) GetLastError(), kUnknownErr
);
3839 require_noerr( err
, exit
);
3842 // Parse the control information. Reject packets received on the wrong interface.
3844 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
3846 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3848 IN_PKTINFO
* ipv4PacketInfo
;
3850 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3854 require_action( ipv4PacketInfo
->ipi_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
3857 dstAddr
.type
= mDNSAddrType_IPv4
;
3858 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3860 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3862 IN6_PKTINFO
* ipv6PacketInfo
;
3864 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3868 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( inIFD
->index
- kIPv6IfIndexBase
), exit
, err
= kMismatchErr
);
3871 dstAddr
.type
= mDNSAddrType_IPv6
;
3872 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3881 addrSize
= sizeof( addr
);
3882 n
= recvfrom( inSock
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
3883 err
= translate_errno( n
> 0, errno_compat(), kUnknownErr
);
3884 require_noerr( err
, exit
);
3886 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
3888 // Dispatch the packet to mDNS.
3890 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3891 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
3892 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3893 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3897 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &inIFD
->interfaceInfo
.ip
, (int) inIFD
->index
);
3900 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3902 end
= ( (mDNSu8
*) &packet
) + n
;
3903 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3909 //===========================================================================================================================
3910 // ProcessingThreadInterfaceListChanged
3911 //===========================================================================================================================
3913 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
3917 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3920 if (inMDNS
->p
->interfaceListChangedCallback
)
3922 inMDNS
->p
->interfaceListChangedCallback(inMDNS
);
3925 mDNSPlatformLock( inMDNS
);
3927 // Tear down the existing interfaces and set up new ones using the new IP info.
3929 err
= TearDownInterfaceList( inMDNS
);
3932 err
= SetupInterfaceList( inMDNS
);
3935 err
= dDNS_Setup( inMDNS
);
3938 // so that LLQs are restarted against the up to date name servers
3940 mDNS_UpdateLLQs( inMDNS
);
3942 mDNSPlatformUnlock( inMDNS
);
3944 // Inform clients of the change.
3946 if( inMDNS
->MainCallback
)
3948 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
3951 // Force mDNS to update.
3953 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
3957 //===========================================================================================================================
3958 // ProcessingThreadComputerDescriptionChanged
3959 //===========================================================================================================================
3960 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
*inMDNS
)
3964 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3967 mDNSPlatformLock( inMDNS
);
3970 SetupNiceName( inMDNS
);
3972 if (inMDNS
->p
->hostDescriptionChangedCallback
)
3974 inMDNS
->p
->hostDescriptionChangedCallback(inMDNS
);
3977 // and reset the event handler
3978 if ((inMDNS
->p
->descKey
!= NULL
) && (inMDNS
->p
->descChangedEvent
))
3980 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3984 mDNSPlatformUnlock( inMDNS
);
3988 //===========================================================================================================================
3989 // ProcessingThreadTCPIPConfigChanged
3990 //===========================================================================================================================
3991 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
)
3995 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3998 mDNSPlatformLock( inMDNS
);
4000 err
= dDNS_Setup( inMDNS
);
4003 // so that LLQs are restarted against the up to date name servers
4005 mDNS_UpdateLLQs( inMDNS
);
4007 // and reset the event handler
4009 if ( ( inMDNS
->p
->tcpipKey
!= NULL
) && ( inMDNS
->p
->tcpipChangedEvent
) )
4011 err
= RegNotifyChangeKeyValue( inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
4015 mDNSPlatformUnlock( inMDNS
);
4019 //===========================================================================================================================
4020 // ProcessingThreadDynDNSConfigChanged
4021 //===========================================================================================================================
4022 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
*inMDNS
)
4026 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
4029 mDNSPlatformLock( inMDNS
);
4031 err
= dDNS_Setup( inMDNS
);
4034 // so that LLQs are restarted against the up to date name servers
4036 mDNS_UpdateLLQs( inMDNS
);
4038 // and reset the event handler
4040 if ((inMDNS
->p
->ddnsKey
!= NULL
) && (inMDNS
->p
->ddnsChangedEvent
))
4042 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
4046 mDNSPlatformUnlock( inMDNS
);
4050 //===========================================================================================================================
4051 // ProcessingThreadRetryVPCCheck
4052 //===========================================================================================================================
4055 ProcessingThreadRetryVPCCheck( mDNS
* inMDNS
)
4057 mStatus err
= mStatus_NoError
;
4059 dlog( kDebugLevelTrace
, DEBUG_NAME
"in ProcessingThreadRetryVPCCheck\n" );
4061 TearDownRetryVPCCheck( inMDNS
);
4063 if ( inMDNS
->p
->vpcCheckCount
< kRetryVPCMax
)
4065 inMDNS
->p
->vpcCheckCount
++;
4067 err
= IsVPCRunning( &inMDNS
->p
->inVirtualPC
);
4068 require_noerr( err
, exit
);
4070 if ( inMDNS
->p
->inVirtualPC
)
4072 ProcessingThreadInterfaceListChanged( inMDNS
);
4080 SetupRetryVPCCheck( inMDNS
);
4090 #pragma mark == Utilities ==
4093 //===========================================================================================================================
4095 //===========================================================================================================================
4097 int getifaddrs( struct ifaddrs
**outAddrs
)
4101 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
4103 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
4104 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
4106 if( !gIPHelperLibraryInstance
)
4108 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
4109 if( gIPHelperLibraryInstance
)
4111 gGetAdaptersAddressesFunctionPtr
=
4112 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
4113 if( !gGetAdaptersAddressesFunctionPtr
)
4117 ok
= FreeLibrary( gIPHelperLibraryInstance
);
4118 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
4119 gIPHelperLibraryInstance
= NULL
;
4124 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
4125 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
4127 if( !gGetAdaptersAddressesFunctionPtr
|| ( ( err
= getifaddrs_ipv6( outAddrs
) ) != mStatus_NoError
) )
4129 err
= getifaddrs_ipv4( outAddrs
);
4130 require_noerr( err
, exit
);
4133 #elif( !TARGET_OS_WINDOWS_CE )
4135 err
= getifaddrs_ipv4( outAddrs
);
4136 require_noerr( err
, exit
);
4140 err
= getifaddrs_ce( outAddrs
);
4141 require_noerr( err
, exit
);
4149 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
4150 //===========================================================================================================================
4152 //===========================================================================================================================
4154 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
4159 struct ifaddrs
* head
;
4160 struct ifaddrs
** next
;
4161 IP_ADAPTER_ADDRESSES
* iaaList
;
4163 IP_ADAPTER_ADDRESSES
* iaa
;
4165 struct ifaddrs
* ifa
;
4167 check( gGetAdaptersAddressesFunctionPtr
);
4173 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
4174 // This loops to handle the case where the interface changes in the window after getting the size, but before the
4175 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
4177 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
4182 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
4183 check( err
== ERROR_BUFFER_OVERFLOW
);
4184 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
4186 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
4187 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
4189 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
4190 if( err
== ERROR_SUCCESS
) break;
4195 require( i
< 100, exit
);
4196 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
4199 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
4202 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
4204 IP_ADAPTER_PREFIX
* firstPrefix
;
4206 if( iaa
->IfIndex
> 0xFFFFFF )
4208 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
4210 if( iaa
->Ipv6IfIndex
> 0xFF )
4212 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
4215 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
4216 // following code to crash when iterating through the prefix list. This seems
4217 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
4218 // This shouldn't happen according to Microsoft docs which states:
4220 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
4222 // So the data structure seems to be corrupted when we return from
4223 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
4224 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
4225 // modify iaa to have the correct values.
4227 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
4229 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
4230 firstPrefix
= iaa
->FirstPrefix
;
4238 // Skip psuedo and tunnel interfaces.
4240 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
4245 // Add each address as a separate interface to emulate the way getifaddrs works.
4247 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
4251 IP_ADAPTER_PREFIX
* prefix
;
4254 family
= addr
->Address
.lpSockaddr
->sa_family
;
4255 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
4257 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4258 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4261 next
= &ifa
->ifa_next
;
4265 size
= strlen( iaa
->AdapterName
) + 1;
4266 ifa
->ifa_name
= (char *) malloc( size
);
4267 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4268 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
4270 // Get interface flags.
4273 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
4274 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
4275 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
4276 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
4279 // <rdar://problem/4045657> Interface index being returned is 512
4281 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
4282 // This code used to shift the IPv4 index up to ensure uniqueness between
4283 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
4284 // then see interface indexes passed back that don't correspond to anything
4285 // that is seen in Win32 APIs or command line tools like "route". As a relatively
4286 // small percentage of developers are actively using IPv6, it seems to
4287 // make sense to make our use of IPv4 as confusion free as possible.
4288 // So now, IPv6 interface indexes will be shifted up by a
4289 // constant value which will serve to uniquely identify them, and we will
4290 // leave IPv4 interface indexes unmodified.
4294 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
4295 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
4305 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
4306 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4307 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
4313 check( ifa
->ifa_addr
);
4315 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
4318 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
4320 if( prefixIndex
== addrIndex
)
4322 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
4323 prefixLength
= prefix
->PrefixLength
;
4331 struct sockaddr_in
* sa4
;
4333 require_action( prefixLength
<= 32, exit
, err
= ERROR_INVALID_DATA
);
4335 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
4336 require_action( sa4
, exit
, err
= WSAENOBUFS
);
4338 sa4
->sin_family
= AF_INET
;
4340 if ( prefixLength
!= 0 )
4342 sa4
->sin_addr
.s_addr
= htonl( 0xFFFFFFFFU
<< ( 32 - prefixLength
) );
4348 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv4 prefixLength is 0\n", __ROUTINE__
);
4349 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &index
, (struct sockaddr
*) sa4
);
4350 require_noerr( err
, exit
);
4353 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
4354 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
4360 struct sockaddr_in6
* sa6
;
4365 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
4367 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
4368 require_action( sa6
, exit
, err
= WSAENOBUFS
);
4369 sa6
->sin6_family
= AF_INET6
;
4371 if( prefixLength
== 0 )
4373 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
4377 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
4379 if( len
>= 8 ) maskByte
= 0xFF;
4380 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
4381 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
4383 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
4400 err
= ERROR_SUCCESS
;
4405 freeifaddrs( head
);
4411 return( (int) err
);
4414 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
4416 #if( !TARGET_OS_WINDOWS_CE )
4417 //===========================================================================================================================
4419 //===========================================================================================================================
4421 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
4427 INTERFACE_INFO
* buffer
;
4428 INTERFACE_INFO
* tempBuffer
;
4429 INTERFACE_INFO
* ifInfo
;
4432 struct ifaddrs
* head
;
4433 struct ifaddrs
** next
;
4434 struct ifaddrs
* ifa
;
4436 sock
= INVALID_SOCKET
;
4441 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4442 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4443 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4445 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4446 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4447 require_noerr( err
, exit
);
4450 size
= 16 * sizeof( INTERFACE_INFO
);
4453 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
4454 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
4455 buffer
= tempBuffer
;
4457 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
4464 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
4466 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
4468 check( actualSize
<= size
);
4469 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
4470 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
4472 // Process the raw interface list and build a linked list of IPv4 interfaces.
4474 for( i
= 0; i
< n
; ++i
)
4476 ifInfo
= &buffer
[ i
];
4477 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
4482 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4483 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4486 next
= &ifa
->ifa_next
;
4490 ifa
->ifa_name
= (char *) malloc( 16 );
4491 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4492 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4494 // Get interface flags.
4496 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4500 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
4502 struct sockaddr_in
* sa4
;
4504 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4505 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4506 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4507 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4509 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4511 // <rdar://problem/4076478> Service won't start on Win2K. The address
4512 // family field was not being initialized.
4514 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4515 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4516 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &ifa
->ifa_extra
.index
, ifa
->ifa_netmask
);
4517 require_noerr( err
, exit
);
4521 // Emulate an interface index.
4523 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4539 freeifaddrs( head
);
4545 if( sock
!= INVALID_SOCKET
)
4547 closesocket( sock
);
4551 #endif // !TARGET_OS_WINDOWS_CE )
4553 #if( TARGET_OS_WINDOWS_CE )
4554 //===========================================================================================================================
4556 //===========================================================================================================================
4558 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
4564 SOCKET_ADDRESS_LIST
* addressList
;
4565 struct ifaddrs
* head
;
4566 struct ifaddrs
** next
;
4567 struct ifaddrs
* ifa
;
4571 sock
= kInvalidSocketRef
;
4576 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4578 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4579 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4580 require_noerr( err
, exit
);
4582 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4583 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4585 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4588 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
4589 require_action( size
> 0, exit
, err
= -1 );
4592 buffer
= calloc( 1, size
);
4593 require_action( buffer
, exit
, err
= -1 );
4595 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4597 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
4598 require_noerr( err
, exit
);
4599 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
4601 // Process the raw interface list and build a linked list of interfaces.
4603 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4605 n
= addressList
->iAddressCount
;
4610 for( i
= 0; i
< n
; ++i
)
4612 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4613 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4616 next
= &ifa
->ifa_next
;
4620 ifa
->ifa_name
= (char *) malloc( 16 );
4621 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4622 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4624 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4626 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
4630 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
4634 struct sockaddr_in
* sa4
;
4636 sa4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
4637 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4638 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4639 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4660 freeifaddrs( head
);
4666 if( sock
!= INVALID_SOCKET
)
4668 closesocket( sock
);
4672 #endif // TARGET_OS_WINDOWS_CE )
4674 //===========================================================================================================================
4676 //===========================================================================================================================
4678 void freeifaddrs( struct ifaddrs
*inIFAs
)
4683 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4685 for( p
= inIFAs
; p
; p
= q
)
4691 free( p
->ifa_name
);
4696 free( p
->ifa_addr
);
4699 if( p
->ifa_netmask
)
4701 free( p
->ifa_netmask
);
4702 p
->ifa_netmask
= NULL
;
4704 if( p
->ifa_broadaddr
)
4706 free( p
->ifa_broadaddr
);
4707 p
->ifa_broadaddr
= NULL
;
4709 if( p
->ifa_dstaddr
)
4711 free( p
->ifa_dstaddr
);
4712 p
->ifa_dstaddr
= NULL
;
4716 free( p
->ifa_data
);
4724 //===========================================================================================================================
4725 // GetPrimaryInterface
4726 //===========================================================================================================================
4729 GetPrimaryInterface()
4731 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4733 BOOL bOrder
= FALSE
;
4737 unsigned long int i
;
4739 // Find out how big our buffer needs to be.
4741 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4742 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4744 // Allocate the memory for the table
4746 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4747 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4749 // Now get the table.
4751 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4752 require_noerr( err
, exit
);
4755 // Search for the row in the table we want.
4757 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4759 // Look for a default route
4761 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4763 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4768 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4769 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4775 if ( pIpForwardTable
!= NULL
)
4777 free( pIpForwardTable
);
4784 //===========================================================================================================================
4785 // AddressToIndexAndMask
4786 //===========================================================================================================================
4789 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4791 // Before calling AddIPAddress we use GetIpAddrTable to get
4792 // an adapter to which we can add the IP.
4794 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4796 mStatus err
= mStatus_UnknownErr
;
4799 // For now, this is only for IPv4 addresses. That is why we can safely cast
4800 // addr's to sockaddr_in.
4802 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4804 // Make an initial call to GetIpAddrTable to get the
4805 // necessary size into the dwSize variable
4807 for ( i
= 0; i
< 100; i
++ )
4809 err
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
4811 if ( err
!= ERROR_INSUFFICIENT_BUFFER
)
4816 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4817 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4820 require_noerr( err
, exit
);
4822 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4824 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4826 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4827 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4828 err
= mStatus_NoError
;
4837 free( pIPAddrTable
);
4844 //===========================================================================================================================
4845 // CanReceiveUnicast
4846 //===========================================================================================================================
4848 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4852 struct sockaddr_in addr
;
4854 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4856 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4857 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4858 ok
= IsValidSocket( sock
);
4861 memset( &addr
, 0, sizeof( addr
) );
4862 addr
.sin_family
= AF_INET
;
4863 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4864 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4866 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4867 close_compat( sock
);
4870 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4875 //===========================================================================================================================
4877 //===========================================================================================================================
4879 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4881 struct ifaddrs
* addrs
= NULL
;
4882 struct ifaddrs
* p
= NULL
;
4884 mDNSBool ret
= mDNSfalse
;
4886 // For now, only works for IPv4 interfaces
4888 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4890 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4892 err
= getifaddrs_ipv4( &addrs
);
4893 require_noerr( err
, exit
);
4895 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4897 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4898 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4900 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4910 freeifaddrs( addrs
);
4917 //===========================================================================================================================
4918 // GetWindowsVersionString
4919 //===========================================================================================================================
4921 OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4923 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4924 #define VER_PLATFORM_WIN32_CE 3
4928 OSVERSIONINFO osInfo
;
4930 const char * versionString
;
4936 versionString
= "unknown Windows version";
4938 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4939 ok
= GetVersionEx( &osInfo
);
4940 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4941 require_noerr( err
, exit
);
4943 platformID
= osInfo
.dwPlatformId
;
4944 majorVersion
= osInfo
.dwMajorVersion
;
4945 minorVersion
= osInfo
.dwMinorVersion
;
4946 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4948 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4950 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4952 versionString
= "Windows 95";
4954 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4956 versionString
= "Windows 95 SP1";
4958 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4960 versionString
= "Windows 95 OSR2";
4962 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4964 versionString
= "Windows 98";
4966 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4968 versionString
= "Windows 98 SP1";
4970 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4972 versionString
= "Windows 98 SE";
4974 else if( minorVersion
== 90 )
4976 versionString
= "Windows ME";
4979 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4981 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4983 versionString
= "Windows NT 3.51";
4985 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4987 versionString
= "Windows NT 4";
4989 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4991 versionString
= "Windows 2000";
4993 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4995 versionString
= "Windows XP";
4997 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4999 versionString
= "Windows Server 2003";
5002 else if( platformID
== VER_PLATFORM_WIN32_CE
)
5004 versionString
= "Windows CE";
5008 if( inBuffer
&& ( inBufferSize
> 0 ) )
5011 strncpy( inBuffer
, versionString
, inBufferSize
);
5012 inBuffer
[ inBufferSize
] = '\0';
5018 //===========================================================================================================================
5020 //===========================================================================================================================
5023 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
5029 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
5040 *string
= (char*) malloc( *stringLen
);
5041 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
5043 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
5047 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
5049 require_noerr_quiet( err
, exit
);
5053 DWORD dwSize
= sizeof( DWORD
);
5055 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
5067 //===========================================================================================================================
5069 //===========================================================================================================================
5071 static mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
5073 struct sockaddr_in6 sa6
;
5074 struct sockaddr_in sa4
;
5078 sa6
.sin6_family
= AF_INET6
;
5079 dwSize
= sizeof( sa6
);
5081 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
5083 if ( err
== mStatus_NoError
)
5085 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa6
);
5086 require_noerr( err
, exit
);
5090 sa4
.sin_family
= AF_INET
;
5091 dwSize
= sizeof( sa4
);
5093 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
5094 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
5095 require_noerr( err
, exit
);
5097 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa4
);
5098 require_noerr( err
, exit
);
5107 //===========================================================================================================================
5109 //===========================================================================================================================
5111 mDNSlocal
struct ifaddrs
*
5112 myGetIfAddrs(int refresh
)
5114 static struct ifaddrs
*ifa
= NULL
;
5131 //===========================================================================================================================
5133 //===========================================================================================================================
5136 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
5138 #if( defined( UNICODE ) || defined( _UNICODE ) )
5142 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
5143 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5144 require_noerr( err
, exit
);
5149 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
5154 //===========================================================================================================================
5155 // WindowsLatin1toUTF8
5156 //===========================================================================================================================
5159 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
5167 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
5169 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
5170 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5171 require_noerr( err
, exit
);
5173 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
5174 require_action( utf16
, exit
, err
= kNoMemoryErr
);
5176 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
5177 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5178 require_noerr( err
, exit
);
5180 // Now convert the temporary UTF-16 to UTF-8.
5182 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
5183 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
5184 require_noerr( err
, exit
);
5187 if( utf16
) free( utf16
);
5192 //===========================================================================================================================
5193 // ConvertUTF8ToLsaString
5194 //===========================================================================================================================
5197 MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
)
5205 output
->Buffer
= NULL
;
5207 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, NULL
, 0 );
5208 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
5209 require_noerr( err
, exit
);
5211 output
->Length
= (USHORT
)( size
* sizeof( wchar_t ) );
5212 output
->Buffer
= (PWCHAR
) malloc( output
->Length
);
5213 require_action( output
->Buffer
, exit
, err
= mStatus_NoMemoryErr
);
5214 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, output
->Buffer
, size
);
5215 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
5216 require_noerr( err
, exit
);
5218 // We're going to subtrace one wchar_t from the size, because we didn't
5219 // include it when we encoded the string
5221 output
->MaximumLength
= output
->Length
;
5222 output
->Length
-= sizeof( wchar_t );
5226 if ( err
&& output
->Buffer
)
5228 free( output
->Buffer
);
5229 output
->Buffer
= NULL
;
5236 //===========================================================================================================================
5237 // ConvertLsaStringToUTF8
5238 //===========================================================================================================================
5241 MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
)
5244 OSStatus err
= kNoErr
;
5246 // The Length field of this structure holds the number of bytes,
5247 // but WideCharToMultiByte expects the number of wchar_t's. So
5248 // we divide by sizeof(wchar_t) to get the correct number.
5250 size
= (size_t) WideCharToMultiByte(CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), NULL
, 0, NULL
, NULL
);
5251 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
5252 require_noerr( err
, exit
);
5254 // Ensure that we have enough space (Add one for trailing '\0')
5256 require_action( ( size
+ 1 ) <= len
, exit
, err
= mStatus_NoMemoryErr
);
5258 // Convert the string
5260 size
= (size_t) WideCharToMultiByte( CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), output
, (int) size
, NULL
, NULL
);
5261 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
5262 require_noerr( err
, exit
);
5264 // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
5265 // although it does return the correct size
5267 output
[size
] = '\0';
5275 //===========================================================================================================================
5276 // FreeTCPConnectionData
5277 //===========================================================================================================================
5280 FreeTCPConnectionData( mDNSTCPConnectionData
* data
)
5284 if ( data
->pendingEvent
)
5286 CloseHandle( data
->pendingEvent
);
5289 if ( data
->sock
!= INVALID_SOCKET
)
5291 closesocket( data
->sock
);