2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.91 2005/04/25 21:34:28 shersche
27 <rdar://problem/4096465> Wide-Area services don't disappear when interface goes away
29 Revision 1.90 2005/04/25 21:18:08 shersche
30 <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.
32 Revision 1.89 2005/04/22 07:32:24 shersche
33 <rdar://problem/4092108> PPP connection disables Bonjour .local lookups
34 <rdar://problem/4093944> mDNSResponder ignores Point-to-Point interfaces
36 Revision 1.88 2005/04/05 03:53:03 shersche
37 <rdar://problem/4066485> Registering with shared secret key doesn't work.
39 Revision 1.87 2005/04/03 08:03:12 shersche
40 <rdar://problem/4076478> mDNSResponder won't start on Windows 2000.
42 Revision 1.86 2005/03/30 07:37:14 shersche
43 Use prefix to compute IPv4 subnet mask, falling back to calling AddressToIndexAndMask only if prefix is zero.
45 Revision 1.85 2005/03/30 07:34:52 shersche
46 <rdar://problem/4045657> Interface index being returned is 512
48 Revision 1.84 2005/03/29 19:19:47 shersche
49 <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.
51 Revision 1.83 2005/03/07 18:27:42 shersche
52 <rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
54 Revision 1.82 2005/03/06 05:20:24 shersche
55 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
57 Revision 1.81 2005/03/04 22:44:53 shersche
58 <rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
60 Revision 1.80 2005/03/03 21:07:38 shersche
61 <rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
63 Revision 1.79 2005/03/03 02:29:00 shersche
64 Use the RegNames.h header file for registry key names
66 Revision 1.78 2005/03/02 04:04:17 shersche
67 Support for multiple browse domains
69 Revision 1.77 2005/02/25 20:02:18 shersche
70 <rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
72 Revision 1.76 2005/02/23 02:59:20 shersche
73 <rdar://problem/4013482> Check to see if locks have been initialized before using them.
75 Revision 1.75 2005/02/16 02:36:25 shersche
76 <rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
78 Revision 1.74 2005/02/08 06:06:16 shersche
79 <rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
81 Revision 1.73 2005/02/01 19:35:43 ksekar
82 Removed obsolete arguments from mDNS_SetSecretForZone
84 Revision 1.72 2005/02/01 01:38:53 shersche
85 Handle null DynDNS configuration more gracefully
87 Revision 1.71 2005/01/27 22:57:57 cheshire
88 Fix compile errors on gcc4
90 Revision 1.70 2005/01/25 08:12:52 shersche
91 <rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
94 Revision 1.69 2005/01/11 04:39:48 shersche
95 Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
97 Revision 1.68 2005/01/11 02:04:48 shersche
98 Gracefully handle when IPv6 is not installed on a user's machine
100 Revision 1.67 2004/12/18 00:51:52 cheshire
101 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
103 Revision 1.66 2004/12/17 23:37:49 cheshire
104 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
105 (and other repetitive configuration changes)
107 Revision 1.65 2004/12/15 07:34:45 shersche
108 Add platform support for IPv4 and IPv6 unicast sockets
110 Revision 1.64 2004/12/15 06:06:15 shersche
111 Fix problem in obtaining IPv6 subnet mask
113 Revision 1.63 2004/11/23 03:39:47 cheshire
114 Let interface name/index mapping capability live directly in JNISupport.c,
115 instead of having to call through to the daemon via IPC to get this information.
117 Revision 1.62 2004/11/12 03:16:41 rpantos
118 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
120 Revision 1.61 2004/11/05 22:54:38 shersche
121 Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
122 Submitted by: Pavel Repin <prepin@gmail.com>
124 Revision 1.60 2004/11/05 22:41:56 shersche
125 Determine subnet mask when populating network interface data structures
126 Submitted by: Pavel Repin <prepin@gmail.com>
129 Revision 1.59 2004/10/28 03:24:42 cheshire
130 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
132 Revision 1.58 2004/10/16 00:17:01 cheshire
133 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
135 Revision 1.57 2004/10/11 21:53:15 shersche
136 <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().
139 Revision 1.56 2004/09/26 23:20:36 ksekar
140 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
142 Revision 1.55 2004/09/21 21:02:57 cheshire
143 Set up ifname before calling mDNS_RegisterInterface()
145 Revision 1.54 2004/09/17 01:08:57 cheshire
146 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
147 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
148 declared in that file are ONLY appropriate to single-address-space embedded applications.
149 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
151 Revision 1.53 2004/09/17 00:19:11 cheshire
152 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
154 Revision 1.52 2004/09/16 00:24:50 cheshire
155 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
157 Revision 1.51 2004/09/14 23:42:37 cheshire
158 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
160 Revision 1.50 2004/08/25 23:36:56 shersche
161 <rdar://problem/3658379> Remove code that retrieves TTL from received packets
164 Revision 1.49 2004/08/25 16:43:29 ksekar
165 Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
168 Revision 1.48 2004/08/14 03:22:43 cheshire
169 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
170 Add GetUserSpecifiedDDNSName() routine
171 Convert ServiceRegDomain to domainname instead of C string
172 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
174 Revision 1.47 2004/08/06 17:33:02 shersche
175 <rdar://problem/3753797> Put correct length of string in first byte of nicelabel
178 Revision 1.46 2004/08/05 05:43:01 shersche
179 <rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
182 Revision 1.45 2004/07/26 22:49:31 ksekar
183 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
185 Revision 1.44 2004/07/26 05:42:50 shersche
186 use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
188 Revision 1.43 2004/07/13 21:24:25 rpantos
189 Fix for <rdar://problem/3701120>.
191 Revision 1.42 2004/06/24 15:23:24 shersche
192 Add InterfaceListChanged callback. This callback is used in Service.c to add link local routes to the routing table
193 Submitted by: herscher
195 Revision 1.41 2004/06/18 05:22:16 rpantos
196 Integrate Scott's changes
198 Revision 1.40 2004/05/26 09:06:07 bradley
199 Retry while building the interface list if it returns an error since the two-step process required to
200 get the interface list could allow a subsequent interface change to come in that window and change the
201 needed size after getting the size, but before getting the list, causing it to return an error.
202 Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
204 Revision 1.39 2004/05/18 23:51:27 cheshire
205 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
207 Revision 1.38 2004/05/13 04:57:48 ksekar
208 Removed unnecessary FreeSearchList function
210 Revision 1.37 2004/05/13 04:54:20 ksekar
211 Unified list copy/free code. Added symetric list for
213 Revision 1.36 2004/05/12 22:03:09 ksekar
214 Made GetSearchDomainList a true platform-layer call (declaration moved
215 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
216 only on non-OSX platforms. Changed call to return a copy of the list
217 to avoid shared memory issues. Added a routine to free the list.
219 Revision 1.35 2004/04/21 02:49:12 cheshire
220 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
222 Revision 1.34 2004/04/15 01:00:05 bradley
223 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
224 without .local name resolving support will need to manually query for A/AAAA records as needed.
226 Revision 1.33 2004/04/14 23:09:29 ksekar
227 Support for TSIG signed dynamic updates.
229 Revision 1.32 2004/04/09 17:40:26 cheshire
230 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
232 Revision 1.31 2004/04/09 00:40:46 bradley
233 Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
235 Revision 1.30 2004/04/09 00:33:58 bradley
236 Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
238 Revision 1.29 2004/03/15 02:07:46 bradley
239 Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
240 handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
241 does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
243 Revision 1.28 2004/03/07 00:26:39 bradley
244 Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
245 Added count assert when building the wait list to catch underruns/overruns if the code is changed.
247 Revision 1.27 2004/01/30 02:44:32 bradley
248 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
249 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
250 are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
251 (it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
252 software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
253 reporting HINFO records with the Windows and mDNSResponder version information.
255 Revision 1.26 2004/01/24 04:59:16 cheshire
256 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
258 Revision 1.25 2003/11/14 20:59:09 cheshire
259 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
260 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
262 Revision 1.24 2003/10/24 23:23:02 bradley
263 Removed legacy port 53 support as it is no longer needed.
265 Revision 1.23 2003/10/14 03:26:12 bradley
266 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
268 Revision 1.22 2003/08/20 06:21:25 bradley
269 Updated to latest internal version of the mDNSWindows platform layer: Added support
270 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
271 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
272 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
273 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
274 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
275 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
276 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
277 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
279 Revision 1.21 2003/08/18 23:09:57 cheshire
280 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
282 Revision 1.20 2003/08/12 19:56:27 cheshire
285 Revision 1.19 2003/08/05 23:58:18 cheshire
286 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
287 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
289 Revision 1.18 2003/07/23 21:16:30 cheshire
290 Removed a couple of debugfs
292 Revision 1.17 2003/07/23 02:23:01 cheshire
293 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
294 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
296 Revision 1.16 2003/07/19 03:15:16 cheshire
297 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
298 and add the obvious trivial implementations to each platform support layer
300 Revision 1.15 2003/07/02 21:20:04 cheshire
301 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
303 Revision 1.14 2003/05/26 03:21:30 cheshire
304 Tidy up address structure naming:
305 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
306 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
307 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
309 Revision 1.13 2003/05/26 03:01:28 cheshire
310 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
312 Revision 1.12 2003/05/06 21:06:05 cheshire
313 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
315 Revision 1.11 2003/05/06 00:00:51 cheshire
316 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
318 Revision 1.10 2003/04/29 00:06:09 cheshire
319 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
321 Revision 1.9 2003/04/26 02:40:01 cheshire
322 Add void LogMsg( const char *format, ... )
324 Revision 1.8 2003/03/22 02:57:44 cheshire
325 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
327 Revision 1.7 2003/03/15 04:40:38 cheshire
328 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
330 Revision 1.6 2003/02/21 01:54:10 cheshire
331 <rdar://problem/3099194> mDNSResponder needs performance improvements
332 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
334 Revision 1.5 2003/02/20 00:59:03 cheshire
335 Brought Windows code up to date so it complies with
336 Josh Graessley's interface changes for IPv6 support.
337 (Actual support for IPv6 on Windows will come later.)
339 Revision 1.4 2002/09/21 20:44:54 zarzycki
342 Revision 1.3 2002/09/20 05:50:45 bradley
343 Multicast DNS platform plugin for Win32
347 - Get unicode name of machine for nice name instead of just the host name.
348 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
349 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
350 - Implement TCP support for truncated packets (only stubs now).
359 #include "CommonServices.h"
360 #include "DebugServices.h"
361 #include "RegNames.h"
364 #include <Iphlpapi.h>
365 #if( !TARGET_OS_WINDOWS_CE )
368 #include <ntsecapi.h>
371 #include "mDNSEmbeddedAPI.h"
373 #include "mDNSWin32.h"
376 #pragma mark == Constants ==
379 //===========================================================================================================================
381 //===========================================================================================================================
383 #define DEBUG_NAME "[mDNSWin32] "
385 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
386 #define MDNS_WINDOWS_ENABLE_IPV4 1
387 #define MDNS_WINDOWS_ENABLE_IPV6 1
388 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
390 #define kMDNSDefaultName "My Computer"
392 #define kWinSockMajorMin 2
393 #define kWinSockMinorMin 2
395 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
396 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
397 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
398 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
399 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
400 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
401 #define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
403 #define kRegistryMaxKeyLength 255
405 #if( !TARGET_OS_WINDOWS_CE )
406 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
409 #define kIPv6IfIndexBase (10000000L)
413 #pragma mark == Prototypes ==
416 //===========================================================================================================================
418 //===========================================================================================================================
420 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
);
421 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
);
422 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
423 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
424 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
425 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
);
426 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
);
427 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
428 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
429 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
430 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
431 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
);
432 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
);
434 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
);
435 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
);
436 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
);
437 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
);
438 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
439 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
);
440 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
);
441 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
* inMDNS
);
442 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
);
443 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
* inMDNS
);
446 // Platform Accessors
452 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
453 struct mDNSPlatformInterfaceInfo
459 typedef struct mDNSTCPConnectionData mDNSTCPConnectionData
;
460 struct mDNSTCPConnectionData
464 TCPConnectionCallback callback
;
467 mDNSTCPConnectionData
* next
;
471 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
472 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
476 typedef struct PolyString PolyString
;
482 PLSA_UNICODE_STRING m_lsa
;
486 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
487 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
490 #if( !TARGET_OS_WINDOWS_CE )
491 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
494 #if( TARGET_OS_WINDOWS_CE )
495 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
498 mDNSlocal DWORD
GetPrimaryInterface();
499 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
500 mDNSlocal mDNSBool
CanReceiveUnicast( void );
501 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
503 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
504 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
505 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
506 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
507 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
508 mDNSlocal OSStatus
MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
);
509 mDNSlocal OSStatus
MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
);
510 mDNSlocal
void FreeTCPConnectionData( mDNSTCPConnectionData
* data
);
517 #pragma mark == Globals ==
520 //===========================================================================================================================
522 //===========================================================================================================================
524 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
525 mDNSs32 mDNSPlatformOneSecond
= 0;
526 mDNSlocal mDNSTCPConnectionData
* gTCPConnectionList
= NULL
;
527 mDNSlocal
int gTCPConnections
= 0;
528 mDNSlocal BOOL gWaitListChanged
= FALSE
;
530 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
533 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
537 PIP_ADAPTER_ADDRESSES inAdapter
,
538 PULONG outBufferSize
);
540 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
541 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
547 #pragma mark == Platform Support ==
550 //===========================================================================================================================
552 //===========================================================================================================================
554 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
559 struct sockaddr_in sa4
;
560 struct sockaddr_in6 sa6
;
564 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
566 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
567 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
569 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
570 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
571 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
572 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
574 // Startup WinSock 2.2 or later.
576 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
577 require_noerr( err
, exit
);
579 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
580 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
582 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
584 // Setup the HINFO HW/SW strings.
586 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
588 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
589 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
591 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
592 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
593 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
594 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
596 // Set up the IPv4 unicast socket
598 inMDNS
->p
->unicastSock4
= INVALID_SOCKET
;
599 inMDNS
->p
->unicastSock4ReadEvent
= NULL
;
600 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
602 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
604 sa4
.sin_family
= AF_INET
;
605 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
606 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
);
608 sa4len
= sizeof( sa4
);
609 err
= getsockname( inMDNS
->p
->unicastSock4
, (struct sockaddr
*) &sa4
, &sa4len
);
610 require_noerr( err
, exit
);
611 inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
612 inMDNS
->p
->unicastSock4ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
613 err
= translate_errno( inMDNS
->p
->unicastSock4ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
614 require_noerr( err
, exit
);
615 err
= WSAEventSelect( inMDNS
->p
->unicastSock4
, inMDNS
->p
->unicastSock4ReadEvent
, FD_READ
);
616 require_noerr( err
, exit
);
617 #if( !TARGET_OS_WINDOWS_CE )
621 err
= WSAIoctl( inMDNS
->p
->unicastSock4
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
622 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock4RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock4RecvMsgPtr
), &size
, NULL
, NULL
);
626 inMDNS
->p
->unicastSock4RecvMsgPtr
= NULL
;
633 // Set up the IPv6 unicast socket
635 inMDNS
->p
->unicastSock6
= INVALID_SOCKET
;
636 inMDNS
->p
->unicastSock6ReadEvent
= NULL
;
637 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
639 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
641 sa6
.sin6_family
= AF_INET6
;
642 sa6
.sin6_addr
= in6addr_any
;
643 sa6
.sin6_scope_id
= 0;
645 // This call will fail if the machine hasn't installed IPv6. In that case,
646 // the error will be WSAEAFNOSUPPORT.
648 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
);
649 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
650 inMDNS
->p
->unicastSock6ReadEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
651 err
= translate_errno( inMDNS
->p
->unicastSock6ReadEvent
, (mStatus
) GetLastError(), kUnknownErr
);
652 require_noerr( err
, exit
);
654 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
656 if ( inMDNS
->p
->unicastSock6
!= INVALID_SOCKET
)
658 sa6len
= sizeof( sa6
);
659 err
= getsockname( inMDNS
->p
->unicastSock6
, (struct sockaddr
*) &sa6
, &sa6len
);
660 require_noerr( err
, exit
);
661 inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
663 err
= WSAEventSelect( inMDNS
->p
->unicastSock6
, inMDNS
->p
->unicastSock6ReadEvent
, FD_READ
);
664 require_noerr( err
, exit
);
666 #if( !TARGET_OS_WINDOWS_CE )
670 err
= WSAIoctl( inMDNS
->p
->unicastSock6
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
,
671 sizeof( kWSARecvMsgGUID
), &inMDNS
->p
->unicastSock6RecvMsgPtr
, sizeof( inMDNS
->p
->unicastSock6RecvMsgPtr
), &size
, NULL
, NULL
);
675 inMDNS
->p
->unicastSock6RecvMsgPtr
= NULL
;
683 // Set up the mDNS thread.
685 err
= SetupSynchronizationObjects( inMDNS
);
686 require_noerr( err
, exit
);
688 err
= SetupThread( inMDNS
);
689 require_noerr( err
, exit
);
693 mDNSCoreInitComplete( inMDNS
, err
);
698 mDNSPlatformClose( inMDNS
);
700 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
704 //===========================================================================================================================
706 //===========================================================================================================================
708 void mDNSPlatformClose( mDNS
* const inMDNS
)
712 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
715 // Tear everything down in reverse order to how it was set up.
717 err
= TearDownThread( inMDNS
);
720 err
= TearDownInterfaceList( inMDNS
);
722 check( !inMDNS
->p
->inactiveInterfaceList
);
724 err
= TearDownSynchronizationObjects( inMDNS
);
727 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
729 if ( inMDNS
->p
->unicastSock4ReadEvent
)
731 CloseHandle( inMDNS
->p
->unicastSock4ReadEvent
);
732 inMDNS
->p
->unicastSock4ReadEvent
= 0;
735 if ( IsValidSocket( inMDNS
->p
->unicastSock4
) )
737 close_compat( inMDNS
->p
->unicastSock4
);
742 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
744 if ( inMDNS
->p
->unicastSock6ReadEvent
)
746 CloseHandle( inMDNS
->p
->unicastSock6ReadEvent
);
747 inMDNS
->p
->unicastSock6ReadEvent
= 0;
750 if ( IsValidSocket( inMDNS
->p
->unicastSock6
) )
752 close_compat( inMDNS
->p
->unicastSock6
);
757 // Free the DLL needed for IPv6 support.
759 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
760 if( gIPHelperLibraryInstance
)
762 gGetAdaptersAddressesFunctionPtr
= NULL
;
764 FreeLibrary( gIPHelperLibraryInstance
);
765 gIPHelperLibraryInstance
= NULL
;
771 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
774 //===========================================================================================================================
775 // mDNSPlatformSendUDP
776 //===========================================================================================================================
780 const mDNS
* const inMDNS
,
781 const void * const inMsg
,
782 const mDNSu8
* const inMsgEnd
,
783 mDNSInterfaceID inInterfaceID
,
784 const mDNSAddr
* inDstIP
,
785 mDNSIPPort inDstPort
)
787 SOCKET sendingsocket
= INVALID_SOCKET
;
788 mStatus err
= mStatus_NoError
;
789 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
790 struct sockaddr_storage addr
;
793 DEBUG_USE_ONLY( inMDNS
);
795 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
801 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
803 if( inDstIP
->type
== mDNSAddrType_IPv4
)
805 struct sockaddr_in
* sa4
;
807 sa4
= (struct sockaddr_in
*) &addr
;
808 sa4
->sin_family
= AF_INET
;
809 sa4
->sin_port
= inDstPort
.NotAnInteger
;
810 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
811 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock4
;
813 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
815 struct sockaddr_in6
* sa6
;
817 sa6
= (struct sockaddr_in6
*) &addr
;
818 sa6
->sin6_family
= AF_INET6
;
819 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
820 sa6
->sin6_flowinfo
= 0;
821 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
822 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
823 sendingsocket
= ifd
? ifd
->sock
: inMDNS
->p
->unicastSock6
;
827 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
828 err
= mStatus_BadParamErr
;
832 if (IsValidSocket(sendingsocket
))
834 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
835 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
839 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
841 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
843 err
= mStatus_TransientErr
;
847 require_noerr( err
, exit
);
856 //===========================================================================================================================
858 //===========================================================================================================================
860 void mDNSPlatformLock( const mDNS
* const inMDNS
)
864 if ( inMDNS
->p
->lockInitialized
)
866 EnterCriticalSection( &inMDNS
->p
->lock
);
870 //===========================================================================================================================
871 // mDNSPlatformUnlock
872 //===========================================================================================================================
874 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
879 if ( inMDNS
->p
->lockInitialized
)
881 check( inMDNS
->p
->threadID
);
883 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
884 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
886 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
890 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
891 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
893 LeaveCriticalSection( &inMDNS
->p
->lock
);
897 //===========================================================================================================================
898 // mDNSPlatformStrCopy
899 //===========================================================================================================================
901 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
906 strcpy( (char *) inDst
, (const char*) inSrc
);
909 //===========================================================================================================================
910 // mDNSPlatformStrLen
911 //===========================================================================================================================
913 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
917 return( (mDNSu32
) strlen( (const char *) inSrc
) );
920 //===========================================================================================================================
921 // mDNSPlatformMemCopy
922 //===========================================================================================================================
924 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
929 memcpy( inDst
, inSrc
, inSize
);
932 //===========================================================================================================================
933 // mDNSPlatformMemSame
934 //===========================================================================================================================
936 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
941 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
944 //===========================================================================================================================
945 // mDNSPlatformMemZero
946 //===========================================================================================================================
948 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
952 memset( inDst
, 0, inSize
);
955 //===========================================================================================================================
956 // mDNSPlatformMemAllocate
957 //===========================================================================================================================
959 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
965 mem
= malloc( inSize
);
971 //===========================================================================================================================
972 // mDNSPlatformMemFree
973 //===========================================================================================================================
975 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
982 //===========================================================================================================================
983 // mDNSPlatformRandomSeed
984 //===========================================================================================================================
986 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
988 return( GetTickCount() );
991 //===========================================================================================================================
992 // mDNSPlatformTimeInit
993 //===========================================================================================================================
995 mDNSexport mStatus
mDNSPlatformTimeInit( void )
997 // No special setup is required on Windows -- we just use GetTickCount().
998 return( mStatus_NoError
);
1001 //===========================================================================================================================
1002 // mDNSPlatformRawTime
1003 //===========================================================================================================================
1005 mDNSs32
mDNSPlatformRawTime( void )
1007 return( (mDNSs32
) GetTickCount() );
1010 //===========================================================================================================================
1012 //===========================================================================================================================
1014 mDNSexport mDNSs32
mDNSPlatformUTC( void )
1016 return ( mDNSs32
) time( NULL
);
1019 //===========================================================================================================================
1020 // mDNSPlatformInterfaceNameToID
1021 //===========================================================================================================================
1023 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
1026 mDNSInterfaceData
* ifd
;
1032 // Search for an interface with the specified name,
1034 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1036 if( strcmp( ifd
->name
, inName
) == 0 )
1041 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1047 *outID
= (mDNSInterfaceID
) ifd
;
1049 err
= mStatus_NoError
;
1055 //===========================================================================================================================
1056 // mDNSPlatformInterfaceIDToInfo
1057 //===========================================================================================================================
1059 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
1062 mDNSInterfaceData
* ifd
;
1068 // Search for an interface with the specified ID,
1070 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1072 if( ifd
== (mDNSInterfaceData
*) inID
)
1077 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
1081 outInfo
->name
= ifd
->name
;
1082 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
1083 err
= mStatus_NoError
;
1089 //===========================================================================================================================
1090 // mDNSPlatformInterfaceIDfromInterfaceIndex
1091 //===========================================================================================================================
1093 mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS
* const inMDNS
, mDNSu32 inIndex
)
1098 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
1100 id
= mDNSInterface_LocalOnly
;
1102 else if( inIndex
!= 0 )
1104 mDNSInterfaceData
* ifd
;
1106 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1108 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
1110 id
= ifd
->interfaceInfo
.InterfaceID
;
1119 //===========================================================================================================================
1120 // mDNSPlatformInterfaceIndexfromInterfaceID
1121 //===========================================================================================================================
1123 mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS
* const inMDNS
, mDNSInterfaceID inID
)
1128 if( inID
== mDNSInterface_LocalOnly
)
1130 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
1134 mDNSInterfaceData
* ifd
;
1136 // Search active interfaces.
1137 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1139 if( (mDNSInterfaceID
) ifd
== inID
)
1141 index
= ifd
->scopeID
;
1146 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
1150 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
1152 if( (mDNSInterfaceID
) ifd
== inID
)
1154 index
= ifd
->scopeID
;
1164 //===========================================================================================================================
1165 // mDNSPlatformTCPConnect
1166 //===========================================================================================================================
1169 mDNSPlatformTCPConnect(
1170 const mDNSAddr
* inDstIP
,
1171 mDNSOpaque16 inDstPort
,
1172 mDNSInterfaceID inInterfaceID
,
1173 TCPConnectionCallback inCallback
,
1177 u_long on
= 1; // "on" for setsockopt
1178 struct sockaddr_in saddr
;
1179 mDNSTCPConnectionData
* tcd
= NULL
;
1180 mStatus err
= mStatus_NoError
;
1182 DEBUG_UNUSED( inInterfaceID
);
1184 *outSock
= INVALID_SOCKET
;
1186 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1188 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1189 return mStatus_UnknownErr
;
1192 // Setup connection data object
1194 tcd
= (mDNSTCPConnectionData
*) malloc( sizeof( mDNSTCPConnectionData
) );
1195 require_action( tcd
, exit
, err
= mStatus_NoMemoryErr
);
1196 memset( tcd
, 0, sizeof( mDNSTCPConnectionData
) );
1198 tcd
->sock
= INVALID_SOCKET
;
1199 tcd
->callback
= inCallback
;
1200 tcd
->context
= inContext
;
1202 bzero(&saddr
, sizeof(saddr
));
1203 saddr
.sin_family
= AF_INET
;
1204 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1205 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1207 // Create the socket
1209 tcd
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
1210 err
= translate_errno( tcd
->sock
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
1211 require_noerr( err
, exit
);
1213 // Set it to be non-blocking
1215 err
= ioctlsocket( tcd
->sock
, FIONBIO
, &on
);
1216 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1217 require_noerr( err
, exit
);
1219 // Try and do connect
1221 err
= connect( tcd
->sock
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1222 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1223 tcd
->connected
= !err
? TRUE
: FALSE
;
1224 tcd
->pendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1225 err
= translate_errno( tcd
->pendingEvent
, GetLastError(), mStatus_UnknownErr
);
1226 require_noerr( err
, exit
);
1227 err
= WSAEventSelect( tcd
->sock
, tcd
->pendingEvent
, FD_CONNECT
|FD_READ
|FD_CLOSE
);
1228 require_noerr( err
, exit
);
1232 tcd
->next
= gTCPConnectionList
;
1233 gTCPConnectionList
= tcd
;
1235 gWaitListChanged
= TRUE
;
1237 *outSock
= (int) tcd
->sock
;
1243 err
= tcd
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1247 FreeTCPConnectionData( tcd
);
1253 //===========================================================================================================================
1254 // mDNSPlatformTCPCloseConnection
1255 //===========================================================================================================================
1257 void mDNSPlatformTCPCloseConnection( int inSock
)
1259 mDNSTCPConnectionData
* tcd
= gTCPConnectionList
;
1260 mDNSTCPConnectionData
* last
= NULL
;
1264 if ( tcd
->sock
== ( SOCKET
) inSock
)
1268 gTCPConnectionList
= tcd
->next
;
1272 last
->next
= tcd
->next
;
1275 FreeTCPConnectionData( tcd
);
1278 gWaitListChanged
= TRUE
;
1288 //===========================================================================================================================
1289 // mDNSPlatformReadTCP
1290 //===========================================================================================================================
1292 int mDNSPlatformReadTCP( int inSock
, void *inBuffer
, int inBufferSize
)
1297 nread
= recv( inSock
, inBuffer
, inBufferSize
, 0);
1298 err
= translate_errno( ( nread
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1299 require_noerr( err
, exit
);
1311 //===========================================================================================================================
1312 // mDNSPlatformWriteTCP
1313 //===========================================================================================================================
1315 int mDNSPlatformWriteTCP( int inSock
, const char *inMsg
, int inMsgSize
)
1320 nsent
= send( inSock
, inMsg
, inMsgSize
, 0 );
1322 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1323 require_noerr( err
, exit
);
1335 //===========================================================================================================================
1336 // dDNSPlatformGetConfig
1337 //===========================================================================================================================
1340 dDNSPlatformGetConfig(domainname
* const fqdn
, domainname
*const regDomain
, DNameListElem
** browseDomains
)
1343 char subKeyName
[kRegistryMaxKeyLength
+ 1];
1357 fqdn
->c
[0] = regDomain
->c
[0] = '\0';
1359 *browseDomains
= NULL
;
1361 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
1362 require_noerr( err
, exit
);
1364 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1365 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1367 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
1369 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
1385 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
, &key
);
1386 require_noerr( err
, exit
);
1388 // Get information about this node
1390 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
1391 require_noerr( err
, exit
);
1393 for ( i
= 0; i
< cSubKeys
; i
++)
1397 dwSize
= kRegistryMaxKeyLength
;
1399 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1403 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
1404 require_noerr( err
, exit
);
1406 dwSize
= sizeof( DWORD
);
1407 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
1409 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
1411 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
1413 dlog( kDebugLevelError
, "bad DDNS browse domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
1417 DNameListElem
* browseDomain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1418 require_action( browseDomain
, exit
, err
= mStatus_NoMemoryErr
);
1420 AssignDomainName(&browseDomain
->name
, &dname
);
1421 browseDomain
->next
= *browseDomains
;
1423 *browseDomains
= browseDomain
;
1427 RegCloseKey( subKey
);
1438 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
, &key
);
1439 require_noerr( err
, exit
);
1441 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
1442 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
1444 if ( !MakeDomainNameFromDNSNameString( regDomain
, name
) || !regDomain
->c
[0] )
1446 dlog( kDebugLevelError
, "bad DDNS registration domain in registry: %s", name
[0] ? name
: "(unknown)");
1454 RegCloseKey( subKey
);
1469 //===========================================================================================================================
1470 // dDNSPlatformSetNameStatus
1471 //===========================================================================================================================
1474 dDNSPlatformSetNameStatus(domainname
*const dname
, mStatus status
)
1476 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1482 ConvertDomainNameToCString(dname
, uname
);
1488 *p
= (char) tolower(*p
);
1489 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1493 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1494 name
= TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\State\\HostNames");
1495 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1496 require_noerr( err
, exit
);
1498 status
= ( status
) ? 0 : 1;
1499 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &status
, sizeof(DWORD
) );
1500 require_noerr( err
, exit
);
1513 //===========================================================================================================================
1514 // dDNSPlatformSetSecretForDomain
1515 //===========================================================================================================================
1518 dDNSPlatformSetSecretForDomain( mDNS
*m
, const domainname
* inDomain
)
1525 LSA_OBJECT_ATTRIBUTES attrs
;
1526 LSA_HANDLE handle
= NULL
;
1530 // Initialize PolyStrings
1532 domain
.m_lsa
= NULL
;
1534 secret
.m_lsa
= NULL
;
1536 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
1538 ConvertDomainNameToCString( inDomain
, domain
.m_utf8
);
1539 dlen
= strlen( domain
.m_utf8
);
1540 for ( i
= 0; i
< dlen
; i
++ )
1542 domain
.m_utf8
[i
] = (char) tolower( domain
.m_utf8
[i
] ); // canonicalize -> lower case
1545 MakeDomainNameFromDNSNameString( &domain
.m_dname
, domain
.m_utf8
);
1547 // attrs are reserved, so initialize to zeroes.
1549 ZeroMemory( &attrs
, sizeof( attrs
) );
1551 // Get a handle to the Policy object on the local system
1553 res
= LsaOpenPolicy( NULL
, &attrs
, POLICY_GET_PRIVATE_INFORMATION
, &handle
);
1554 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1555 require_noerr( err
, exit
);
1557 // Get the encrypted data
1559 domain
.m_lsa
= ( PLSA_UNICODE_STRING
) malloc( sizeof( LSA_UNICODE_STRING
) );
1560 require_action( domain
.m_lsa
!= NULL
, exit
, err
= mStatus_NoMemoryErr
);
1561 err
= MakeLsaStringFromUTF8String( domain
.m_lsa
, domain
.m_utf8
);
1562 require_noerr( err
, exit
);
1566 res
= LsaRetrievePrivateData( handle
, domain
.m_lsa
, &key
.m_lsa
);
1567 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1568 require_noerr_quiet( err
, exit
);
1570 // Convert the key to a domainname
1572 err
= MakeUTF8StringFromLsaString( key
.m_utf8
, sizeof( key
.m_utf8
), key
.m_lsa
);
1573 require_noerr( err
, exit
);
1574 MakeDomainNameFromDNSNameString( &key
.m_dname
, key
.m_utf8
);
1576 // Retrieve the secret
1578 res
= LsaRetrievePrivateData( handle
, key
.m_lsa
, &secret
.m_lsa
);
1579 err
= translate_errno( res
== 0, LsaNtStatusToWinError( res
), kUnknownErr
);
1580 require_noerr_quiet( err
, exit
);
1582 // Convert the secret to UTF8 string
1584 err
= MakeUTF8StringFromLsaString( secret
.m_utf8
, sizeof( secret
.m_utf8
), secret
.m_lsa
);
1585 require_noerr( err
, exit
);
1587 // And finally, tell the core about this secret
1589 debugf("Setting shared secret for zone %s with key %##s", domain
.m_utf8
, key
.m_dname
.c
);
1590 mDNS_SetSecretForZone( m
, &domain
.m_dname
, &key
.m_dname
, secret
.m_utf8
);
1594 if ( domain
.m_lsa
!= NULL
)
1596 if ( domain
.m_lsa
->Buffer
!= NULL
)
1598 free( domain
.m_lsa
->Buffer
);
1601 free( domain
.m_lsa
);
1604 if ( key
.m_lsa
!= NULL
)
1606 LsaFreeMemory( key
.m_lsa
);
1609 if ( secret
.m_lsa
!= NULL
)
1611 LsaFreeMemory( secret
.m_lsa
);
1622 //===========================================================================================================================
1623 // dDNSPlatformGetSearchDomainList
1624 //===========================================================================================================================
1627 dDNSPlatformGetSearchDomainList( void )
1629 char * searchList
= NULL
;
1630 DWORD searchListLen
;
1631 DNameListElem
* head
= NULL
;
1632 DNameListElem
* current
= NULL
;
1637 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1638 require_noerr( err
, exit
);
1640 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1641 require_noerr( err
, exit
);
1643 // Windows separates the search domains with ','
1645 tok
= strtok( searchList
, "," );
1650 if ( MakeDomainNameFromDNSNameString( &domain
, tok
) )
1652 DNameListElem
* last
= current
;
1654 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1655 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1657 AssignDomainName( ¤t
->name
, &domain
);
1658 current
->next
= NULL
;
1667 last
->next
= current
;
1671 tok
= strtok( NULL
, "," );
1690 //===========================================================================================================================
1691 // dDNSPlatformGetReverseMapSearchDomainList
1692 //===========================================================================================================================
1695 dDNSPlatformGetReverseMapSearchDomainList( void )
1697 DNameListElem
* head
= NULL
;
1698 DNameListElem
* current
= NULL
;
1699 struct ifaddrs
* ifa
;
1702 ifa
= myGetIfAddrs( 1 );
1707 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !dDNS_SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1713 if (!dDNS_SetupAddr(&netmask
, ifa
->ifa_netmask
))
1715 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1716 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1717 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1718 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1720 if ( MakeDomainNameFromDNSNameString( &domain
, buffer
) )
1722 DNameListElem
* last
= current
;
1724 current
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1725 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1727 AssignDomainName( ¤t
->name
, &domain
);
1728 current
->next
= NULL
;
1737 last
->next
= current
;
1743 ifa
= ifa
->ifa_next
;
1752 //===========================================================================================================================
1753 // dDNSPlatformGetDNSServers
1754 //===========================================================================================================================
1757 dDNSPlatformGetDNSServers( void )
1759 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1760 FIXED_INFO
* fixedInfo
= NULL
;
1762 IP_ADDR_STRING
* dnsServerList
;
1763 IP_ADDR_STRING
* ipAddr
;
1764 IPAddrListElem
* head
= NULL
;
1765 IPAddrListElem
* current
= NULL
;
1770 // Get the primary interface.
1772 index
= GetPrimaryInterface();
1774 // This should have the interface index of the primary index. Fall back in cases where
1775 // it can't be determined.
1781 while ( GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
) == ERROR_BUFFER_OVERFLOW
)
1783 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1784 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1787 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1791 bufLen
= sizeof( FIXED_INFO
);
1797 GlobalFree( fixedInfo
);
1801 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1803 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1805 if ( ( err
!= ERROR_BUFFER_OVERFLOW
) || ( i
++ == 100 ) )
1811 require_noerr( err
, exit
);
1813 dnsServerList
= &fixedInfo
->DnsServerList
;
1816 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1819 IPAddrListElem
* last
= current
;
1821 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1828 current
= (IPAddrListElem
*) malloc( sizeof( IPAddrListElem
) );
1829 require_action( current
, exit
, err
= mStatus_NoMemoryErr
);
1831 memcpy( ¤t
->addr
, &addr
, sizeof( mDNSAddr
) );
1832 current
->next
= NULL
;
1841 last
->next
= current
;
1849 free( pAdapterInfo
);
1854 GlobalFree( fixedInfo
);
1861 //===========================================================================================================================
1862 // dDNSPlatformGetDomainName
1863 //===========================================================================================================================
1866 dDNSPlatformGetDomainName( void )
1868 FIXED_INFO
* fixedInfo
= NULL
;
1869 ULONG bufLen
= sizeof( FIXED_INFO
);
1870 DNameListElem
* head
= NULL
;
1878 GlobalFree( fixedInfo
);
1882 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1884 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1886 if ( ( err
!= ERROR_BUFFER_OVERFLOW
) || ( i
++ == 100 ) )
1892 require_noerr( err
, exit
);
1894 if ( fixedInfo
->DomainName
)
1898 if ( MakeDomainNameFromDNSNameString( &dname
, fixedInfo
->DomainName
) || !dname
.c
[0] )
1900 head
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
1901 require_action( head
, exit
, err
= mStatus_NoMemoryErr
);
1903 AssignDomainName( &head
->name
, &dname
);
1908 dlog( kDebugLevelError
, "bad DDNS host name from domain name: %s", fixedInfo
->DomainName
);
1916 GlobalFree( fixedInfo
);
1923 //===========================================================================================================================
1924 // dDNSPlatformRegisterSplitDNS
1925 //===========================================================================================================================
1928 dDNSPlatformRegisterSplitDNS( mDNS
* m
)
1932 return mStatus_UnsupportedErr
;
1936 //===========================================================================================================================
1937 // dDNSPlatformGetPrimaryInterface
1938 //===========================================================================================================================
1941 dDNSPlatformGetPrimaryInterface( mDNS
* m
, mDNSAddr
* primary
, mDNSAddr
* router
)
1943 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1944 IP_ADAPTER_INFO
* pAdapter
;
1945 DWORD bufLen
= sizeof( IP_ADAPTER_INFO
);
1949 mStatus err
= mStatus_NoError
;
1953 pAdapterInfo
= NULL
;
1956 for ( i
= 0; i
< 100; i
++ )
1960 free( pAdapterInfo
);
1961 pAdapterInfo
= NULL
;
1964 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
1965 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1967 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1969 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1975 index
= GetPrimaryInterface();
1977 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
1979 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
1980 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
1981 pAdapter
->GatewayList
.IpAddress
.String
&&
1982 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
1983 ( StringToAddress( primary
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
1984 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
1985 ( !index
|| ( pAdapter
->Index
== index
) ) )
1987 // Found one that will work
1998 free( pAdapterInfo
);
2005 //===========================================================================================================================
2006 // dDNSPlatformDefaultBrowseDomainChanged
2007 //===========================================================================================================================
2010 dDNSPlatformDefaultBrowseDomainChanged( const domainname
*d
, mDNSBool add
)
2013 DEBUG_UNUSED( add
);
2015 // This is a no-op on Windows
2019 //===========================================================================================================================
2020 // dDNSPlatformDefaultRegDomainChanged
2021 //===========================================================================================================================
2024 dDNSPlatformDefaultRegDomainChanged( const domainname
* d
, mDNSBool add
)
2027 DEBUG_UNUSED( add
);
2029 // This is a no-op on Windows
2037 //===========================================================================================================================
2039 //===========================================================================================================================
2041 #if( MDNS_DEBUGMSGS )
2042 void debugf_( const char *inFormat
, ... )
2048 va_start( args
, inFormat
);
2049 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2052 dlog( kDebugLevelInfo
, "%s\n", buffer
);
2056 //===========================================================================================================================
2058 //===========================================================================================================================
2060 #if( MDNS_DEBUGMSGS > 1 )
2061 void verbosedebugf_( const char *inFormat
, ... )
2067 va_start( args
, inFormat
);
2068 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2071 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
2075 //===========================================================================================================================
2077 //===========================================================================================================================
2080 void LogMsg( const char *inFormat, ... )
2086 va_start( args, inFormat );
2087 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2090 dlog( kDebugLevelWarning, "%s\n", buffer );
2096 #pragma mark == Platform Internals ==
2099 //===========================================================================================================================
2100 // SetupSynchronizationObjects
2101 //===========================================================================================================================
2103 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
2107 InitializeCriticalSection( &inMDNS
->p
->lock
);
2108 inMDNS
->p
->lockInitialized
= mDNStrue
;
2110 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2111 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2112 require_noerr( err
, exit
);
2114 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2115 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2116 require_noerr( err
, exit
);
2118 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2119 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2120 require_noerr( err
, exit
);
2122 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2123 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2124 require_noerr( err
, exit
);
2129 TearDownSynchronizationObjects( inMDNS
);
2134 //===========================================================================================================================
2135 // TearDownSynchronizationObjects
2136 //===========================================================================================================================
2138 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
2140 if( inMDNS
->p
->quitEvent
)
2142 CloseHandle( inMDNS
->p
->quitEvent
);
2143 inMDNS
->p
->quitEvent
= 0;
2145 if( inMDNS
->p
->cancelEvent
)
2147 CloseHandle( inMDNS
->p
->cancelEvent
);
2148 inMDNS
->p
->cancelEvent
= 0;
2150 if( inMDNS
->p
->interfaceListChangedEvent
)
2152 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
2153 inMDNS
->p
->interfaceListChangedEvent
= 0;
2155 if( inMDNS
->p
->wakeupEvent
)
2157 CloseHandle( inMDNS
->p
->wakeupEvent
);
2158 inMDNS
->p
->wakeupEvent
= 0;
2160 if( inMDNS
->p
->lockInitialized
)
2162 DeleteCriticalSection( &inMDNS
->p
->lock
);
2163 inMDNS
->p
->lockInitialized
= mDNSfalse
;
2165 return( mStatus_NoError
);
2169 //===========================================================================================================================
2171 //===========================================================================================================================
2173 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
)
2176 char tempString
[ 256 ];
2181 // Set up the nice name.
2182 tempString
[ 0 ] = '\0';
2185 // First try and open the registry key that contains the computer description value
2186 if (inMDNS
->p
->descKey
== NULL
)
2188 LPCTSTR s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2189 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &inMDNS
->p
->descKey
);
2190 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2194 inMDNS
->p
->descKey
= NULL
;
2198 // if we opened it...
2199 if (inMDNS
->p
->descKey
!= NULL
)
2202 DWORD descSize
= sizeof( desc
);
2204 // look for the computer description
2205 err
= RegQueryValueEx(inMDNS
->p
->descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2209 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2218 // if we can't find it in the registry, then use the hostname of the machine
2219 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2221 err
= gethostname( tempString
, sizeof( tempString
) - 1 );
2222 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2226 err
= WindowsLatin1toUTF8( tempString
, utf8
, sizeof( utf8
) );
2235 // if we can't get the hostname
2236 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2238 // Invalidate name so fall back to a default name.
2240 strcpy( utf8
, kMDNSDefaultName
);
2243 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2244 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2245 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2247 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2253 //===========================================================================================================================
2255 //===========================================================================================================================
2257 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2260 char tempString
[ 256 ];
2261 domainlabel tempLabel
;
2265 // Set up the nice name.
2266 tempString
[ 0 ] = '\0';
2268 // use the hostname of the machine
2269 err
= gethostname( tempString
, sizeof( tempString
) - 1 );
2270 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2272 // if we can't get the hostname
2273 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2275 // Invalidate name so fall back to a default name.
2277 strcpy( tempString
, kMDNSDefaultName
);
2280 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2281 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2282 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2284 // Set up the host name.
2286 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2287 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2289 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2291 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2294 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2296 mDNS_SetFQDN( inMDNS
);
2298 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2303 //===========================================================================================================================
2305 //===========================================================================================================================
2307 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2313 err
= SetupNiceName( inMDNS
);
2316 err
= SetupHostName( inMDNS
);
2323 //===========================================================================================================================
2324 // SetupInterfaceList
2325 //===========================================================================================================================
2327 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2330 mDNSInterfaceData
** next
;
2331 mDNSInterfaceData
* ifd
;
2332 struct ifaddrs
* addrs
;
2334 struct ifaddrs
* loopbackv4
;
2335 struct ifaddrs
* loopbackv6
;
2340 mDNSBool foundUnicastSock4DestAddr
;
2341 mDNSBool foundUnicastSock6DestAddr
;
2343 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2348 foundv4
= mDNSfalse
;
2349 foundv6
= mDNSfalse
;
2350 foundUnicastSock4DestAddr
= mDNSfalse
;
2351 foundUnicastSock6DestAddr
= mDNSfalse
;
2353 // Tear down any existing interfaces that may be set up.
2355 TearDownInterfaceList( inMDNS
);
2357 // Set up the name of this machine.
2359 err
= SetupName( inMDNS
);
2362 // Set up the interface list change notification.
2364 err
= SetupNotifications( inMDNS
);
2367 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2368 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2370 err
= getifaddrs( &addrs
);
2371 require_noerr( err
, exit
);
2375 next
= &inMDNS
->p
->interfaceList
;
2377 flagMask
= IFF_UP
| IFF_MULTICAST
;
2378 flagTest
= IFF_UP
| IFF_MULTICAST
;
2380 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2381 for( p
= addrs
; p
; p
= p
->ifa_next
)
2383 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2387 if( p
->ifa_flags
& IFF_LOOPBACK
)
2395 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2396 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2398 err
= SetupInterface( inMDNS
, p
, &ifd
);
2399 require_noerr( err
, exit
);
2401 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2402 // register him, but we also want to note that we haven't found a v4 interface
2403 // so that we register loopback so same host operations work
2405 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2410 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2411 // of determing the destination address of a packet that is sent to us.
2412 // For multicast packets, that's easy to determine. But for the unicast
2413 // sockets, we'll fake it by taking the address of the first interface
2414 // that is successfully setup.
2416 if ( !foundUnicastSock4DestAddr
)
2418 inMDNS
->p
->unicastSock4DestAddr
= ifd
->interfaceInfo
.ip
;
2419 foundUnicastSock4DestAddr
= TRUE
;
2424 ++inMDNS
->p
->interfaceCount
;
2428 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2430 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2431 for( p
= addrs
; p
; p
= p
->ifa_next
)
2433 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2437 if( p
->ifa_flags
& IFF_LOOPBACK
)
2445 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2446 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2448 err
= SetupInterface( inMDNS
, p
, &ifd
);
2449 require_noerr( err
, exit
);
2451 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2452 // register him, but we also want to note that we haven't found a v4 interface
2453 // so that we register loopback so same host operations work
2455 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2460 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2461 // of determing the destination address of a packet that is sent to us.
2462 // For multicast packets, that's easy to determine. But for the unicast
2463 // sockets, we'll fake it by taking the address of the first interface
2464 // that is successfully setup.
2466 if ( !foundUnicastSock6DestAddr
)
2468 inMDNS
->p
->unicastSock6DestAddr
= ifd
->interfaceInfo
.ip
;
2469 foundUnicastSock6DestAddr
= TRUE
;
2474 ++inMDNS
->p
->interfaceCount
;
2478 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2480 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2482 flagMask
|= IFF_LOOPBACK
;
2483 flagTest
|= IFF_LOOPBACK
;
2485 for( p
= addrs
; p
; p
= p
->ifa_next
)
2487 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2491 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2502 if ( !foundv4
&& loopbackv4
)
2504 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2505 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2507 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2508 require_noerr( err
, exit
);
2510 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2512 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2513 // of determing the destination address of a packet that is sent to us.
2514 // For multicast packets, that's easy to determine. But for the unicast
2515 // sockets, we'll fake it by taking the address of the first interface
2516 // that is successfully setup.
2518 if ( !foundUnicastSock4DestAddr
)
2520 inMDNS
->p
->unicastSock4DestAddr
= ifd
->defaultAddr
;
2521 foundUnicastSock4DestAddr
= TRUE
;
2527 ++inMDNS
->p
->interfaceCount
;
2533 TearDownInterfaceList( inMDNS
);
2537 freeifaddrs( addrs
);
2539 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2543 //===========================================================================================================================
2544 // TearDownInterfaceList
2545 //===========================================================================================================================
2547 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2550 mDNSInterfaceData
** p
;
2551 mDNSInterfaceData
* ifd
;
2553 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2557 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2558 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2559 // so that remove events that occur after an interface goes away can still report the correct interface.
2561 p
= &inMDNS
->p
->inactiveInterfaceList
;
2565 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2571 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2576 // Tear down interface list change notifications.
2578 err
= TearDownNotifications( inMDNS
);
2581 // Tear down all the interfaces.
2583 while( inMDNS
->p
->interfaceList
)
2585 ifd
= inMDNS
->p
->interfaceList
;
2586 inMDNS
->p
->interfaceList
= ifd
->next
;
2588 TearDownInterface( inMDNS
, ifd
);
2590 inMDNS
->p
->interfaceCount
= 0;
2592 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2593 return( mStatus_NoError
);
2596 //===========================================================================================================================
2598 //===========================================================================================================================
2600 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2602 mDNSInterfaceData
* ifd
;
2603 mDNSInterfaceData
* p
;
2608 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2612 check( inIFA
->ifa_addr
);
2615 // Allocate memory for the interface and initialize it.
2617 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2618 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2619 ifd
->sock
= kInvalidSocketRef
;
2620 ifd
->index
= inIFA
->ifa_extra
.index
;
2621 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2622 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2623 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2624 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2626 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2627 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2629 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2630 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2631 // on a large configured network, which means there's a good chance that most or all the other devices on that
2632 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2633 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2634 // devices on a large configured network, so we are willing to make that sacrifice.
2636 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2637 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2639 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2641 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2643 if (!ifd
->interfaceInfo
.InterfaceID
)
2645 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2648 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2649 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2650 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2652 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2659 if ( !ifd
->interfaceInfo
.InterfaceID
)
2661 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2664 // Set up a socket for this interface (if needed).
2666 if( ifd
->interfaceInfo
.McastTxRx
)
2668 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &sock
);
2669 require_noerr( err
, exit
);
2671 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2673 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2675 #if( !TARGET_OS_WINDOWS_CE )
2679 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
2680 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
2683 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
2688 // Set up the read pending event and associate it so we can block until data is available for this socket.
2690 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2691 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2692 require_noerr( err
, exit
);
2694 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
2695 require_noerr( err
, exit
);
2699 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2701 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2702 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2703 require_noerr( err
, exit
);
2706 // Register this interface with mDNS.
2708 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2709 require_noerr( err
, exit
);
2711 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2712 require_noerr( err
, exit
);
2714 ifd
->interfaceInfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
2716 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, 0 );
2717 require_noerr( err
, exit
);
2718 ifd
->hostRegistered
= mDNStrue
;
2720 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2730 TearDownInterface( inMDNS
, ifd
);
2732 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2736 //===========================================================================================================================
2737 // TearDownInterface
2738 //===========================================================================================================================
2740 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2747 // Deregister this interface with mDNS.
2749 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2751 if( inIFD
->hostRegistered
)
2753 inIFD
->hostRegistered
= mDNSfalse
;
2754 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
);
2757 // Tear down the multicast socket.
2759 if( inIFD
->readPendingEvent
)
2761 CloseHandle( inIFD
->readPendingEvent
);
2762 inIFD
->readPendingEvent
= 0;
2766 inIFD
->sock
= kInvalidSocketRef
;
2767 if( IsValidSocket( sock
) )
2769 close_compat( sock
);
2772 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2773 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2775 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2777 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2778 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2779 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2783 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2786 return( mStatus_NoError
);
2789 //===========================================================================================================================
2791 //===========================================================================================================================
2793 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2799 DEBUG_UNUSED( inMDNS
);
2801 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2803 check( outSocketRef
);
2805 // Set up an IPv4 or IPv6 UDP socket.
2807 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2808 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2809 require_noerr( err
, exit
);
2811 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2812 // if we're creating a multicast socket
2814 if ( port
.NotAnInteger
)
2817 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2818 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2821 if( inAddr
->sa_family
== AF_INET
)
2824 struct sockaddr_in sa4
;
2825 struct ip_mreq mreqv4
;
2827 // Bind the socket to the desired port
2829 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
2830 memset( &sa4
, 0, sizeof( sa4
) );
2831 sa4
.sin_family
= AF_INET
;
2832 sa4
.sin_port
= port
.NotAnInteger
;
2833 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2835 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
2836 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2838 // Turn on option to receive destination addresses and receiving interface.
2841 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
2842 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2844 if (port
.NotAnInteger
)
2846 // Join the all-DNS multicast group so we receive Multicast DNS packets
2848 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
2849 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
2850 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
2851 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2853 // Specify the interface to send multicast packets on this socket.
2855 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
2856 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
2857 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2859 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2862 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2863 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2866 // Send unicast packets with TTL 255 (helps against spoofing).
2869 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
2870 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2872 // Send multicast packets with TTL 255 (helps against spoofing).
2875 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
2876 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2879 else if( inAddr
->sa_family
== AF_INET6
)
2881 struct sockaddr_in6
* sa6p
;
2882 struct sockaddr_in6 sa6
;
2883 struct ipv6_mreq mreqv6
;
2885 sa6p
= (struct sockaddr_in6
*) inAddr
;
2887 // Bind the socket to the desired port
2889 memset( &sa6
, 0, sizeof( sa6
) );
2890 sa6
.sin6_family
= AF_INET6
;
2891 sa6
.sin6_port
= port
.NotAnInteger
;
2892 sa6
.sin6_flowinfo
= 0;
2893 sa6
.sin6_addr
= sa6p
->sin6_addr
;
2894 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
2896 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
2897 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
2899 // Turn on option to receive destination addresses and receiving interface.
2902 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
2903 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2905 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
2906 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
2907 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
2909 #if( defined( IPV6_V6ONLY ) )
2911 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
2912 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2915 if ( port
.NotAnInteger
)
2917 // Join the all-DNS multicast group so we receive Multicast DNS packets.
2919 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroupv6
);
2920 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
2921 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
2922 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2924 // Specify the interface to send multicast packets on this socket.
2926 option
= (int) sa6p
->sin6_scope_id
;
2927 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
2928 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2930 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2933 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
2934 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2937 // Send unicast packets with TTL 255 (helps against spoofing).
2940 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
2941 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2943 // Send multicast packets with TTL 255 (helps against spoofing).
2946 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
2947 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2951 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
2952 err
= kUnsupportedErr
;
2958 *outSocketRef
= sock
;
2959 sock
= kInvalidSocketRef
;
2960 err
= mStatus_NoError
;
2963 if( IsValidSocket( sock
) )
2965 close_compat( sock
);
2970 //===========================================================================================================================
2972 //===========================================================================================================================
2974 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
2981 if( inSA
->sa_family
== AF_INET
)
2983 struct sockaddr_in
* sa4
;
2985 sa4
= (struct sockaddr_in
*) inSA
;
2986 outIP
->type
= mDNSAddrType_IPv4
;
2987 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
2990 outPort
->NotAnInteger
= sa4
->sin_port
;
2992 err
= mStatus_NoError
;
2994 else if( inSA
->sa_family
== AF_INET6
)
2996 struct sockaddr_in6
* sa6
;
2998 sa6
= (struct sockaddr_in6
*) inSA
;
2999 outIP
->type
= mDNSAddrType_IPv6
;
3000 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
3001 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
3003 outIP
->ip
.v6
.w
[ 1 ] = 0;
3007 outPort
->NotAnInteger
= sa6
->sin6_port
;
3009 err
= mStatus_NoError
;
3013 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
3014 err
= mStatus_BadParamErr
;
3019 //===========================================================================================================================
3020 // SetupNotifications
3021 //===========================================================================================================================
3023 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
3027 unsigned long param
;
3032 // Register to listen for address list changes.
3034 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3035 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
3036 require_noerr( err
, exit
);
3037 inMDNS
->p
->interfaceListChangedSocket
= sock
;
3039 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
3040 // when a change to the interface list is detected.
3043 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
3044 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3045 require_noerr( err
, exit
);
3049 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
3052 check( errno_compat() == WSAEWOULDBLOCK
);
3055 err
= WSAEventSelect( sock
, inMDNS
->p
->interfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
3056 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
3057 require_noerr( err
, exit
);
3059 inMDNS
->p
->descChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
3060 err
= translate_errno( inMDNS
->p
->descChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3061 require_noerr( err
, exit
);
3063 if (inMDNS
->p
->descKey
!= NULL
)
3065 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3066 require_noerr( err
, exit
);
3069 // This will catch all changes to tcp/ip networking, including changes to the domain search list
3071 inMDNS
->p
->tcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3072 err
= translate_errno( inMDNS
->p
->tcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3073 require_noerr( err
, exit
);
3075 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS
->p
->tcpipKey
);
3076 require_noerr( err
, exit
);
3078 err
= RegNotifyChangeKeyValue(inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3079 require_noerr( err
, exit
);
3081 // This will catch all changes to ddns configuration
3083 inMDNS
->p
->ddnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
3084 err
= translate_errno( inMDNS
->p
->ddnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3085 require_noerr( err
, exit
);
3087 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters\\DynDNS\\Setup"), &inMDNS
->p
->ddnsKey
);
3088 require_noerr( err
, exit
);
3090 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3091 require_noerr( err
, exit
);
3096 TearDownNotifications( inMDNS
);
3101 //===========================================================================================================================
3102 // TearDownNotifications
3103 //===========================================================================================================================
3105 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
3107 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
3109 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
3110 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
3113 if ( inMDNS
->p
->descChangedEvent
!= NULL
)
3115 CloseHandle( inMDNS
->p
->descChangedEvent
);
3116 inMDNS
->p
->descChangedEvent
= NULL
;
3119 if ( inMDNS
->p
->descKey
!= NULL
)
3121 RegCloseKey( inMDNS
->p
->descKey
);
3122 inMDNS
->p
->descKey
= NULL
;
3125 if ( inMDNS
->p
->tcpipChangedEvent
!= NULL
)
3127 CloseHandle( inMDNS
->p
->tcpipChangedEvent
);
3128 inMDNS
->p
->tcpipChangedEvent
= NULL
;
3131 if ( inMDNS
->p
->ddnsChangedEvent
!= NULL
)
3133 CloseHandle( inMDNS
->p
->ddnsChangedEvent
);
3134 inMDNS
->p
->ddnsChangedEvent
= NULL
;
3137 if ( inMDNS
->p
->ddnsKey
!= NULL
)
3139 RegCloseKey( inMDNS
->p
->ddnsKey
);
3140 inMDNS
->p
->ddnsKey
= NULL
;
3143 return( mStatus_NoError
);
3150 //===========================================================================================================================
3152 //===========================================================================================================================
3154 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
3157 HANDLE threadHandle
;
3161 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
3163 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3164 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3166 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
3167 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
3168 require_noerr( err
, exit
);
3170 inMDNS
->p
->initStatus
= mStatus_Invalid
;
3172 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3173 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3175 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
3176 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
3177 require_noerr( err
, exit
);
3179 result
= WaitForSingleObject( inMDNS
->p
->initEvent
, INFINITE
);
3180 err
= translate_errno( result
== WAIT_OBJECT_0
, (mStatus
) GetLastError(), kUnknownErr
);
3181 require_noerr( err
, exit
);
3182 err
= inMDNS
->p
->initStatus
;
3183 require_noerr( err
, exit
);
3186 if( inMDNS
->p
->initEvent
)
3188 CloseHandle( inMDNS
->p
->initEvent
);
3189 inMDNS
->p
->initEvent
= 0;
3191 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
3195 //===========================================================================================================================
3197 //===========================================================================================================================
3199 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
3201 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3202 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3204 if( inMDNS
->p
->cancelEvent
)
3209 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
3210 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3212 if( inMDNS
->p
->quitEvent
)
3214 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
3215 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
3218 return( mStatus_NoError
);
3221 //===========================================================================================================================
3223 //===========================================================================================================================
3225 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
3237 m
= (mDNS
*) inParam
;
3238 err
= ProcessingThreadInitialize( m
);
3239 require_noerr( err
, exit
);
3244 // Set up the list of objects we'll be waiting on.
3248 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
3249 require_noerr( err
, exit
);
3251 // Main processing loop.
3253 gWaitListChanged
= FALSE
;
3257 // Give the mDNS core a chance to do its work and determine next event time.
3259 mDNSs32 interval
= mDNS_Execute(m
) - mDNS_TimeNow(m
);
3261 if ( gWaitListChanged
)
3266 if (m
->p
->idleThreadCallback
)
3268 interval
= m
->p
->idleThreadCallback(m
, interval
);
3270 if (interval
< 0) interval
= 0;
3271 else if (interval
> (0x7FFFFFFF / 1000)) interval
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
3272 else interval
= (interval
* 1000) / mDNSPlatformOneSecond
;
3274 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3276 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
3277 if( result
== WAIT_TIMEOUT
)
3279 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3281 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
3284 else if( result
== kWaitListCancelEvent
)
3286 // Cancel event. Set the done flag and break to exit.
3288 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
3292 else if( result
== kWaitListInterfaceListChangedEvent
)
3294 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3296 ProcessingThreadInterfaceListChanged( m
);
3299 else if( result
== kWaitListWakeupEvent
)
3301 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3303 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
3306 else if ( result
== kWaitListComputerDescriptionEvent
)
3309 // The computer description might have changed
3311 ProcessingThreadComputerDescriptionChanged( m
);
3314 else if ( result
== kWaitListTCPIPEvent
)
3317 // The TCP/IP might have changed
3319 ProcessingThreadTCPIPConfigChanged( m
);
3322 else if ( result
== kWaitListDynDNSEvent
)
3325 // The DynDNS config might have changed
3327 ProcessingThreadDynDNSConfigChanged( m
);
3334 // Socket data available event. Determine which socket and process the packet.
3336 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
3337 dlog( kDebugLevelChatty
, DEBUG_NAME
"socket data available on socket index %d\n", waitItemIndex
);
3338 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
3339 if( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
3341 HANDLE signaledObject
;
3343 mDNSInterfaceData
* ifd
;
3344 mDNSTCPConnectionData
* tcd
;
3346 signaledObject
= waitList
[ waitItemIndex
];
3348 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3349 if ( m
->p
->unicastSock4ReadEvent
== signaledObject
)
3351 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock4
);
3356 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3357 if ( m
->p
->unicastSock6ReadEvent
== signaledObject
)
3359 ProcessingThreadProcessPacket( m
, NULL
, m
->p
->unicastSock6
);
3364 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3366 if( ifd
->readPendingEvent
== signaledObject
)
3368 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
3373 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3375 if ( tcd
->pendingEvent
== signaledObject
)
3377 mDNSBool connect
= FALSE
;
3379 if ( !tcd
->connected
)
3381 tcd
->connected
= mDNStrue
;
3385 tcd
->callback( ( int ) tcd
->sock
, tcd
->context
, connect
);
3397 // Unexpected wait result.
3399 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
3404 // Release the wait list.
3414 // Signal the quit event to indicate that the thread is finished.
3417 wasSet
= SetEvent( m
->p
->quitEvent
);
3418 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3420 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3421 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3423 _endthreadex_compat( 0 );
3427 //===========================================================================================================================
3428 // ProcessingThreadInitialize
3429 //===========================================================================================================================
3431 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
3436 inMDNS
->p
->threadID
= GetCurrentThreadId();
3438 err
= SetupInterfaceList( inMDNS
);
3439 require_noerr( err
, exit
);
3441 err
= dDNS_Setup( inMDNS
);
3442 require_noerr( err
, exit
);
3444 err
= dDNS_InitDNSConfig( inMDNS
);
3445 require_noerr( err
, exit
);
3451 TearDownInterfaceList( inMDNS
);
3453 inMDNS
->p
->initStatus
= err
;
3455 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
3456 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
3460 //===========================================================================================================================
3461 // ProcessingThreadSetupWaitList
3462 //===========================================================================================================================
3464 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
3469 HANDLE
* waitItemPtr
;
3470 mDNSInterfaceData
* ifd
;
3471 mDNSTCPConnectionData
* tcd
;
3473 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
3476 check( outWaitList
);
3477 check( outWaitListCount
);
3479 // Allocate an array to hold all the objects to wait on.
3481 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->interfaceCount
+ gTCPConnections
;
3482 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
3483 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
3484 waitItemPtr
= waitList
;
3486 // Add the fixed wait items to the beginning of the list.
3488 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
3489 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
3490 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
3491 *waitItemPtr
++ = inMDNS
->p
->descChangedEvent
;
3492 *waitItemPtr
++ = inMDNS
->p
->tcpipChangedEvent
;
3493 *waitItemPtr
++ = inMDNS
->p
->ddnsChangedEvent
;
3495 // Append all the dynamic wait items to the list.
3496 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3497 *waitItemPtr
++ = inMDNS
->p
->unicastSock4ReadEvent
;
3500 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3501 *waitItemPtr
++ = inMDNS
->p
->unicastSock6ReadEvent
;
3504 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
3506 *waitItemPtr
++ = ifd
->readPendingEvent
;
3509 for ( tcd
= gTCPConnectionList
; tcd
; tcd
= tcd
->next
)
3511 *waitItemPtr
++ = tcd
->pendingEvent
;
3514 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
3516 *outWaitList
= waitList
;
3517 *outWaitListCount
= waitListCount
;
3519 err
= mStatus_NoError
;
3526 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
3530 //===========================================================================================================================
3531 // ProcessingThreadProcessPacket
3532 //===========================================================================================================================
3534 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
)
3537 const mDNSInterfaceID iid
= inIFD
? inIFD
->interfaceInfo
.InterfaceID
: NULL
;
3538 LPFN_WSARECVMSG recvMsgPtr
;
3544 struct sockaddr_storage addr
;
3550 check( IsValidSocket( inSock
) );
3552 // Set up the default in case the packet info options are not supported or reported correctly.
3556 recvMsgPtr
= inIFD
->wsaRecvMsgFunctionPtr
;
3557 dstAddr
= inIFD
->defaultAddr
;
3558 dstPort
= MulticastDNSPort
;
3561 else if ( inSock
== inMDNS
->p
->unicastSock4
)
3563 recvMsgPtr
= inMDNS
->p
->unicastSock4RecvMsgPtr
;
3564 dstAddr
= inMDNS
->p
->unicastSock4DestAddr
;
3565 dstPort
= zeroIPPort
;
3568 else if ( inSock
== inMDNS
->p
->unicastSock6
)
3570 recvMsgPtr
= inMDNS
->p
->unicastSock6RecvMsgPtr
;
3571 dstAddr
= inMDNS
->p
->unicastSock6DestAddr
;
3572 dstPort
= zeroIPPort
;
3577 dlog( kDebugLevelError
, DEBUG_NAME
"packet received on unknown socket\n" );
3581 #if( !TARGET_OS_WINDOWS_CE )
3586 uint8_t controlBuffer
[ 128 ];
3588 LPWSACMSGHDR header
;
3590 // Set up the buffer and read the packet.
3592 msg
.name
= (LPSOCKADDR
) &addr
;
3593 msg
.namelen
= (INT
) sizeof( addr
);
3594 buf
.buf
= (char *) &packet
;
3595 buf
.len
= (u_long
) sizeof( packet
);
3596 msg
.lpBuffers
= &buf
;
3597 msg
.dwBufferCount
= 1;
3598 msg
.Control
.buf
= (char *) controlBuffer
;
3599 msg
.Control
.len
= (u_long
) sizeof( controlBuffer
);
3602 err
= recvMsgPtr( inSock
, &msg
, &size
, NULL
, NULL
);
3603 err
= translate_errno( err
== 0, (OSStatus
) GetLastError(), kUnknownErr
);
3604 require_noerr( err
, exit
);
3607 // Parse the control information. Reject packets received on the wrong interface.
3609 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
3611 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3613 IN_PKTINFO
* ipv4PacketInfo
;
3615 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3619 require_action( ipv4PacketInfo
->ipi_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
3622 dstAddr
.type
= mDNSAddrType_IPv4
;
3623 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3625 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3627 IN6_PKTINFO
* ipv6PacketInfo
;
3629 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3633 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( inIFD
->index
- kIPv6IfIndexBase
), exit
, err
= kMismatchErr
);
3636 dstAddr
.type
= mDNSAddrType_IPv6
;
3637 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3646 addrSize
= sizeof( addr
);
3647 n
= recvfrom( inSock
, (char *) &packet
, sizeof( packet
), 0, (struct sockaddr
*) &addr
, &addrSize
);
3648 err
= translate_errno( n
> 0, errno_compat(), kUnknownErr
);
3649 require_noerr( err
, exit
);
3651 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
3653 // Dispatch the packet to mDNS.
3655 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3656 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", n
);
3657 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3658 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3662 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &inIFD
->interfaceInfo
.ip
, (int) inIFD
->index
);
3665 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3667 end
= ( (mDNSu8
*) &packet
) + n
;
3668 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3674 //===========================================================================================================================
3675 // ProcessingThreadInterfaceListChanged
3676 //===========================================================================================================================
3678 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
3682 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3685 if (inMDNS
->p
->interfaceListChangedCallback
)
3687 inMDNS
->p
->interfaceListChangedCallback(inMDNS
);
3690 mDNSPlatformLock( inMDNS
);
3692 // Tear down the existing interfaces and set up new ones using the new IP info.
3694 err
= TearDownInterfaceList( inMDNS
);
3697 err
= SetupInterfaceList( inMDNS
);
3700 err
= dDNS_Setup( inMDNS
);
3703 // so that LLQs are restarted against the up to date name servers
3705 mDNS_UpdateLLQs( inMDNS
);
3707 mDNSPlatformUnlock( inMDNS
);
3709 // Inform clients of the change.
3711 if( inMDNS
->MainCallback
)
3713 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
3716 // Force mDNS to update.
3718 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
3722 //===========================================================================================================================
3723 // ProcessingThreadComputerDescriptionChanged
3724 //===========================================================================================================================
3725 mDNSlocal
void ProcessingThreadComputerDescriptionChanged( mDNS
*inMDNS
)
3729 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3732 mDNSPlatformLock( inMDNS
);
3735 SetupNiceName( inMDNS
);
3737 if (inMDNS
->p
->hostDescriptionChangedCallback
)
3739 inMDNS
->p
->hostDescriptionChangedCallback(inMDNS
);
3742 // and reset the event handler
3743 if ((inMDNS
->p
->descKey
!= NULL
) && (inMDNS
->p
->descChangedEvent
))
3745 err
= RegNotifyChangeKeyValue(inMDNS
->p
->descKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->descChangedEvent
, TRUE
);
3749 mDNSPlatformUnlock( inMDNS
);
3753 //===========================================================================================================================
3754 // ProcessingThreadTCPIPConfigChanged
3755 //===========================================================================================================================
3756 mDNSlocal
void ProcessingThreadTCPIPConfigChanged( mDNS
* inMDNS
)
3760 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3763 mDNSPlatformLock( inMDNS
);
3765 err
= dDNS_Setup( inMDNS
);
3768 // so that LLQs are restarted against the up to date name servers
3770 mDNS_UpdateLLQs( inMDNS
);
3772 // and reset the event handler
3774 if ( ( inMDNS
->p
->tcpipKey
!= NULL
) && ( inMDNS
->p
->tcpipChangedEvent
) )
3776 err
= RegNotifyChangeKeyValue( inMDNS
->p
->tcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->tcpipChangedEvent
, TRUE
);
3780 mDNSPlatformUnlock( inMDNS
);
3784 //===========================================================================================================================
3785 // ProcessingThreadDynDNSConfigChanged
3786 //===========================================================================================================================
3787 mDNSlocal
void ProcessingThreadDynDNSConfigChanged( mDNS
*inMDNS
)
3791 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3794 mDNSPlatformLock( inMDNS
);
3796 err
= dDNS_Setup( inMDNS
);
3799 // so that LLQs are restarted against the up to date name servers
3801 mDNS_UpdateLLQs( inMDNS
);
3803 // and reset the event handler
3805 if ((inMDNS
->p
->ddnsKey
!= NULL
) && (inMDNS
->p
->ddnsChangedEvent
))
3807 err
= RegNotifyChangeKeyValue(inMDNS
->p
->ddnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, inMDNS
->p
->ddnsChangedEvent
, TRUE
);
3811 mDNSPlatformUnlock( inMDNS
);
3817 #pragma mark == Utilities ==
3820 //===========================================================================================================================
3822 //===========================================================================================================================
3824 int getifaddrs( struct ifaddrs
**outAddrs
)
3828 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
3830 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3831 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3833 if( !gIPHelperLibraryInstance
)
3835 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
3836 if( gIPHelperLibraryInstance
)
3838 gGetAdaptersAddressesFunctionPtr
=
3839 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
3840 if( !gGetAdaptersAddressesFunctionPtr
)
3844 ok
= FreeLibrary( gIPHelperLibraryInstance
);
3845 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
3846 gIPHelperLibraryInstance
= NULL
;
3851 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3853 if( gGetAdaptersAddressesFunctionPtr
)
3855 err
= getifaddrs_ipv6( outAddrs
);
3856 require_noerr( err
, exit
);
3860 err
= getifaddrs_ipv4( outAddrs
);
3861 require_noerr( err
, exit
);
3864 #elif( !TARGET_OS_WINDOWS_CE )
3866 err
= getifaddrs_ipv4( outAddrs
);
3867 require_noerr( err
, exit
);
3871 err
= getifaddrs_ce( outAddrs
);
3872 require_noerr( err
, exit
);
3880 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3881 //===========================================================================================================================
3883 //===========================================================================================================================
3885 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
3890 struct ifaddrs
* head
;
3891 struct ifaddrs
** next
;
3892 IP_ADAPTER_ADDRESSES
* iaaList
;
3894 IP_ADAPTER_ADDRESSES
* iaa
;
3896 struct ifaddrs
* ifa
;
3898 check( gGetAdaptersAddressesFunctionPtr
);
3904 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3905 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3906 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3908 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
3913 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
3914 check( err
== ERROR_BUFFER_OVERFLOW
);
3915 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
3917 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
3918 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
3920 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
3921 if( err
== ERROR_SUCCESS
) break;
3926 require( i
< 100, exit
);
3927 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
3930 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
3933 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
3935 IP_ADAPTER_PREFIX
* firstPrefix
;
3937 if( iaa
->IfIndex
> 0xFFFFFF )
3939 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
3941 if( iaa
->Ipv6IfIndex
> 0xFF )
3943 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
3946 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3947 // following code to crash when iterating through the prefix list. This seems
3948 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3949 // This shouldn't happen according to Microsoft docs which states:
3951 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3953 // So the data structure seems to be corrupted when we return from
3954 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3955 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3956 // modify iaa to have the correct values.
3958 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
3960 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
3961 firstPrefix
= iaa
->FirstPrefix
;
3969 // Skip psuedo and tunnel interfaces.
3971 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
3976 // Add each address as a separate interface to emulate the way getifaddrs works.
3978 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
3982 IP_ADAPTER_PREFIX
* prefix
;
3985 family
= addr
->Address
.lpSockaddr
->sa_family
;
3986 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
3988 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3989 require_action( ifa
, exit
, err
= WSAENOBUFS
);
3992 next
= &ifa
->ifa_next
;
3996 size
= strlen( iaa
->AdapterName
) + 1;
3997 ifa
->ifa_name
= (char *) malloc( size
);
3998 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
3999 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
4001 // Get interface flags.
4004 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
4005 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
4006 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
4007 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
4010 // <rdar://problem/4045657> Interface index being returned is 512
4012 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
4013 // This code used to shift the IPv4 index up to ensure uniqueness between
4014 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
4015 // then see interface indexes passed back that don't correspond to anything
4016 // that is seen in Win32 APIs or command line tools like "route". As a relatively
4017 // small percentage of developers are actively using IPv6, it seems to
4018 // make sense to make our use of IPv4 as confusion free as possible.
4019 // So now, IPv6 interface indexes will be shifted up by a
4020 // constant value which will serve to uniquely identify them, and we will
4021 // leave IPv4 interface indexes unmodified.
4025 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
4026 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
4036 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
4037 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4038 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
4044 check( ifa
->ifa_addr
);
4046 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
4049 for( prefixIndex
= 0, prefix
= firstPrefix
; prefix
; ++prefixIndex
, prefix
= prefix
->Next
)
4051 if( prefixIndex
== addrIndex
)
4053 check_string( prefix
->Address
.lpSockaddr
->sa_family
== family
, "addr family != netmask family" );
4054 prefixLength
= prefix
->PrefixLength
;
4062 struct sockaddr_in
* sa4
;
4064 require_action( prefixLength
<= 32, exit
, err
= ERROR_INVALID_DATA
);
4066 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
4067 require_action( sa4
, exit
, err
= WSAENOBUFS
);
4069 sa4
->sin_family
= AF_INET
;
4071 if ( prefixLength
!= 0 )
4073 sa4
->sin_addr
.s_addr
= htonl( 0xFFFFFFFFU
<< ( 32 - prefixLength
) );
4079 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv4 prefixLength is 0\n", __ROUTINE__
);
4080 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &index
, (struct sockaddr
*) sa4
);
4081 require_noerr( err
, exit
);
4084 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
4085 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
4091 struct sockaddr_in6
* sa6
;
4096 require_action( prefixLength
<= 128, exit
, err
= ERROR_INVALID_DATA
);
4098 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
4099 require_action( sa6
, exit
, err
= WSAENOBUFS
);
4100 sa6
->sin6_family
= AF_INET6
;
4102 if( prefixLength
== 0 )
4104 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__
);
4108 for( len
= (int) prefixLength
; len
> 0; len
-= 8 )
4110 if( len
>= 8 ) maskByte
= 0xFF;
4111 else maskByte
= (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
4112 sa6
->sin6_addr
.s6_addr
[ maskIndex
++ ] = maskByte
;
4114 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
4131 err
= ERROR_SUCCESS
;
4136 freeifaddrs( head
);
4142 return( (int) err
);
4145 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
4147 #if( !TARGET_OS_WINDOWS_CE )
4148 //===========================================================================================================================
4150 //===========================================================================================================================
4152 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
4158 INTERFACE_INFO
* buffer
;
4159 INTERFACE_INFO
* tempBuffer
;
4160 INTERFACE_INFO
* ifInfo
;
4163 struct ifaddrs
* head
;
4164 struct ifaddrs
** next
;
4165 struct ifaddrs
* ifa
;
4167 sock
= INVALID_SOCKET
;
4172 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4173 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4174 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4176 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4177 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4178 require_noerr( err
, exit
);
4181 size
= 16 * sizeof( INTERFACE_INFO
);
4184 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
4185 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
4186 buffer
= tempBuffer
;
4188 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
4195 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
4197 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
4199 check( actualSize
<= size
);
4200 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
4201 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
4203 // Process the raw interface list and build a linked list of IPv4 interfaces.
4205 for( i
= 0; i
< n
; ++i
)
4207 ifInfo
= &buffer
[ i
];
4208 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
4213 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4214 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4217 next
= &ifa
->ifa_next
;
4221 ifa
->ifa_name
= (char *) malloc( 16 );
4222 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4223 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4225 // Get interface flags.
4227 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
4231 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
4233 struct sockaddr_in
* sa4
;
4235 sa4
= &ifInfo
->iiAddress
.AddressIn
;
4236 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4237 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4238 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4240 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4242 // <rdar://problem/4076478> Service won't start on Win2K. The address
4243 // family field was not being initialized.
4245 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4246 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4247 err
= AddressToIndexAndMask( ifa
->ifa_addr
, &ifa
->ifa_extra
.index
, ifa
->ifa_netmask
);
4248 require_noerr( err
, exit
);
4252 // Emulate an interface index.
4254 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4270 freeifaddrs( head
);
4276 if( sock
!= INVALID_SOCKET
)
4278 closesocket( sock
);
4282 #endif // !TARGET_OS_WINDOWS_CE )
4284 #if( TARGET_OS_WINDOWS_CE )
4285 //===========================================================================================================================
4287 //===========================================================================================================================
4289 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
4295 SOCKET_ADDRESS_LIST
* addressList
;
4296 struct ifaddrs
* head
;
4297 struct ifaddrs
** next
;
4298 struct ifaddrs
* ifa
;
4302 sock
= kInvalidSocketRef
;
4307 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4309 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4310 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4311 require_noerr( err
, exit
);
4313 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4314 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4316 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4319 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
4320 require_action( size
> 0, exit
, err
= -1 );
4323 buffer
= calloc( 1, size
);
4324 require_action( buffer
, exit
, err
= -1 );
4326 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4328 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, buffer
, size
, &size
, NULL
, NULL
);
4329 require_noerr( err
, exit
);
4330 addressList
= (SOCKET_ADDRESS_LIST
*) buffer
;
4332 // Process the raw interface list and build a linked list of interfaces.
4334 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4336 n
= addressList
->iAddressCount
;
4341 for( i
= 0; i
< n
; ++i
)
4343 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
4344 require_action( ifa
, exit
, err
= WSAENOBUFS
);
4347 next
= &ifa
->ifa_next
;
4351 ifa
->ifa_name
= (char *) malloc( 16 );
4352 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
4353 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
4355 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4357 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
4361 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
4365 struct sockaddr_in
* sa4
;
4367 sa4
= (struct sockaddr_in
*) addressList
->Address
[ i
].lpSockaddr
;
4368 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
4369 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
4370 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4391 freeifaddrs( head
);
4397 if( sock
!= INVALID_SOCKET
)
4399 closesocket( sock
);
4403 #endif // TARGET_OS_WINDOWS_CE )
4405 //===========================================================================================================================
4407 //===========================================================================================================================
4409 void freeifaddrs( struct ifaddrs
*inIFAs
)
4414 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4416 for( p
= inIFAs
; p
; p
= q
)
4422 free( p
->ifa_name
);
4427 free( p
->ifa_addr
);
4430 if( p
->ifa_netmask
)
4432 free( p
->ifa_netmask
);
4433 p
->ifa_netmask
= NULL
;
4435 if( p
->ifa_broadaddr
)
4437 free( p
->ifa_broadaddr
);
4438 p
->ifa_broadaddr
= NULL
;
4440 if( p
->ifa_dstaddr
)
4442 free( p
->ifa_dstaddr
);
4443 p
->ifa_dstaddr
= NULL
;
4447 free( p
->ifa_data
);
4455 //===========================================================================================================================
4456 // GetPrimaryInterface
4457 //===========================================================================================================================
4460 GetPrimaryInterface()
4462 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4464 BOOL bOrder
= FALSE
;
4468 unsigned long int i
;
4470 // Find out how big our buffer needs to be.
4472 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4473 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4475 // Allocate the memory for the table
4477 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4478 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4480 // Now get the table.
4482 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4483 require_noerr( err
, exit
);
4486 // Search for the row in the table we want.
4488 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4490 // Look for a default route
4492 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4494 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4499 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4500 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4506 if ( pIpForwardTable
!= NULL
)
4508 free( pIpForwardTable
);
4515 //===========================================================================================================================
4516 // AddressToIndexAndMask
4517 //===========================================================================================================================
4520 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4522 // Before calling AddIPAddress we use GetIpAddrTable to get
4523 // an adapter to which we can add the IP.
4525 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4527 mStatus err
= mStatus_UnknownErr
;
4530 // For now, this is only for IPv4 addresses. That is why we can safely cast
4531 // addr's to sockaddr_in.
4533 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4535 // Make an initial call to GetIpAddrTable to get the
4536 // necessary size into the dwSize variable
4538 while ( GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 ) == ERROR_INSUFFICIENT_BUFFER
)
4540 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4541 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4544 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4546 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4548 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4549 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4550 err
= mStatus_NoError
;
4559 free( pIPAddrTable
);
4566 //===========================================================================================================================
4567 // CanReceiveUnicast
4568 //===========================================================================================================================
4570 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4574 struct sockaddr_in addr
;
4576 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4578 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4579 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4580 ok
= IsValidSocket( sock
);
4583 memset( &addr
, 0, sizeof( addr
) );
4584 addr
.sin_family
= AF_INET
;
4585 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4586 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4588 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4589 close_compat( sock
);
4592 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4597 //===========================================================================================================================
4599 //===========================================================================================================================
4601 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4603 struct ifaddrs
* addrs
= NULL
;
4604 struct ifaddrs
* p
= NULL
;
4606 mDNSBool ret
= mDNSfalse
;
4608 // For now, only works for IPv4 interfaces
4610 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4612 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4614 err
= getifaddrs_ipv4( &addrs
);
4615 require_noerr( err
, exit
);
4617 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4619 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4620 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4622 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4632 freeifaddrs( addrs
);
4639 //===========================================================================================================================
4640 // GetWindowsVersionString
4641 //===========================================================================================================================
4643 OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4645 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4646 #define VER_PLATFORM_WIN32_CE 3
4650 OSVERSIONINFO osInfo
;
4652 const char * versionString
;
4658 versionString
= "unknown Windows version";
4660 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4661 ok
= GetVersionEx( &osInfo
);
4662 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4663 require_noerr( err
, exit
);
4665 platformID
= osInfo
.dwPlatformId
;
4666 majorVersion
= osInfo
.dwMajorVersion
;
4667 minorVersion
= osInfo
.dwMinorVersion
;
4668 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4670 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4672 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4674 versionString
= "Windows 95";
4676 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4678 versionString
= "Windows 95 SP1";
4680 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4682 versionString
= "Windows 95 OSR2";
4684 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4686 versionString
= "Windows 98";
4688 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4690 versionString
= "Windows 98 SP1";
4692 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4694 versionString
= "Windows 98 SE";
4696 else if( minorVersion
== 90 )
4698 versionString
= "Windows ME";
4701 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4703 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4705 versionString
= "Windows NT 3.51";
4707 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4709 versionString
= "Windows NT 4";
4711 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4713 versionString
= "Windows 2000";
4715 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4717 versionString
= "Windows XP";
4719 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4721 versionString
= "Windows Server 2003";
4724 else if( platformID
== VER_PLATFORM_WIN32_CE
)
4726 versionString
= "Windows CE";
4730 if( inBuffer
&& ( inBufferSize
> 0 ) )
4733 strncpy( inBuffer
, versionString
, inBufferSize
);
4734 inBuffer
[ inBufferSize
] = '\0';
4740 //===========================================================================================================================
4742 //===========================================================================================================================
4745 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
4751 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
4762 *string
= (char*) malloc( *stringLen
);
4763 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
4765 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
4769 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
4771 require_noerr_quiet( err
, exit
);
4775 DWORD dwSize
= sizeof( DWORD
);
4777 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
4789 //===========================================================================================================================
4791 //===========================================================================================================================
4793 static mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
4795 struct sockaddr_in6 sa6
;
4796 struct sockaddr_in sa4
;
4800 sa6
.sin6_family
= AF_INET6
;
4801 dwSize
= sizeof( sa6
);
4803 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
4805 if ( err
== mStatus_NoError
)
4807 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa6
);
4808 require_noerr( err
, exit
);
4812 sa4
.sin_family
= AF_INET
;
4813 dwSize
= sizeof( sa4
);
4815 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
4816 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
4817 require_noerr( err
, exit
);
4819 err
= dDNS_SetupAddr( ip
, (struct sockaddr
*) &sa4
);
4820 require_noerr( err
, exit
);
4829 //===========================================================================================================================
4831 //===========================================================================================================================
4833 mDNSlocal
struct ifaddrs
*
4834 myGetIfAddrs(int refresh
)
4836 static struct ifaddrs
*ifa
= NULL
;
4853 //===========================================================================================================================
4855 //===========================================================================================================================
4858 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
4860 #if( defined( UNICODE ) || defined( _UNICODE ) )
4864 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4865 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4866 require_noerr( err
, exit
);
4871 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
4876 //===========================================================================================================================
4877 // WindowsLatin1toUTF8
4878 //===========================================================================================================================
4881 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
4889 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4891 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
4892 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4893 require_noerr( err
, exit
);
4895 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
4896 require_action( utf16
, exit
, err
= kNoMemoryErr
);
4898 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
4899 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4900 require_noerr( err
, exit
);
4902 // Now convert the temporary UTF-16 to UTF-8.
4904 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4905 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4906 require_noerr( err
, exit
);
4909 if( utf16
) free( utf16
);
4914 //===========================================================================================================================
4915 // ConvertUTF8ToLsaString
4916 //===========================================================================================================================
4919 MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output
, const char * input
)
4927 output
->Buffer
= NULL
;
4929 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, NULL
, 0 );
4930 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
4931 require_noerr( err
, exit
);
4933 output
->Length
= (USHORT
)( size
* sizeof( wchar_t ) );
4934 output
->Buffer
= (PWCHAR
) malloc( output
->Length
);
4935 require_action( output
->Buffer
, exit
, err
= mStatus_NoMemoryErr
);
4936 size
= MultiByteToWideChar( CP_UTF8
, 0, input
, -1, output
->Buffer
, size
);
4937 err
= translate_errno( size
> 0, GetLastError(), kUnknownErr
);
4938 require_noerr( err
, exit
);
4940 // We're going to subtrace one wchar_t from the size, because we didn't
4941 // include it when we encoded the string
4943 output
->MaximumLength
= output
->Length
;
4944 output
->Length
-= sizeof( wchar_t );
4948 if ( err
&& output
->Buffer
)
4950 free( output
->Buffer
);
4951 output
->Buffer
= NULL
;
4958 //===========================================================================================================================
4959 // ConvertLsaStringToUTF8
4960 //===========================================================================================================================
4963 MakeUTF8StringFromLsaString( char * output
, size_t len
, PLSA_UNICODE_STRING input
)
4966 OSStatus err
= kNoErr
;
4968 // The Length field of this structure holds the number of bytes,
4969 // but WideCharToMultiByte expects the number of wchar_t's. So
4970 // we divide by sizeof(wchar_t) to get the correct number.
4972 size
= (size_t) WideCharToMultiByte(CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), NULL
, 0, NULL
, NULL
);
4973 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
4974 require_noerr( err
, exit
);
4976 // Ensure that we have enough space (Add one for trailing '\0')
4978 require_action( ( size
+ 1 ) <= len
, exit
, err
= mStatus_NoMemoryErr
);
4980 // Convert the string
4982 size
= (size_t) WideCharToMultiByte( CP_UTF8
, 0, input
->Buffer
, ( input
->Length
/ sizeof( wchar_t ) ), output
, (int) size
, NULL
, NULL
);
4983 err
= translate_errno( size
!= 0, GetLastError(), kUnknownErr
);
4984 require_noerr( err
, exit
);
4986 // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
4987 // although it does return the correct size
4989 output
[size
] = '\0';
4997 //===========================================================================================================================
4998 // FreeTCPConnectionData
4999 //===========================================================================================================================
5002 FreeTCPConnectionData( mDNSTCPConnectionData
* data
)
5006 if ( data
->pendingEvent
)
5008 CloseHandle( data
->pendingEvent
);
5011 if ( data
->sock
!= INVALID_SOCKET
)
5013 closesocket( data
->sock
);