]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/mDNSWin32.c
mDNSResponder-107.3.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / mDNSWin32.c
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: mDNSWin32.c,v $
26 Revision 1.83 2005/03/07 18:27:42 shersche
27 <rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
28
29 Revision 1.82 2005/03/06 05:20:24 shersche
30 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
31
32 Revision 1.81 2005/03/04 22:44:53 shersche
33 <rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
34
35 Revision 1.80 2005/03/03 21:07:38 shersche
36 <rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
37
38 Revision 1.79 2005/03/03 02:29:00 shersche
39 Use the RegNames.h header file for registry key names
40
41 Revision 1.78 2005/03/02 04:04:17 shersche
42 Support for multiple browse domains
43
44 Revision 1.77 2005/02/25 20:02:18 shersche
45 <rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
46
47 Revision 1.76 2005/02/23 02:59:20 shersche
48 <rdar://problem/4013482> Check to see if locks have been initialized before using them.
49
50 Revision 1.75 2005/02/16 02:36:25 shersche
51 <rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
52
53 Revision 1.74 2005/02/08 06:06:16 shersche
54 <rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
55
56 Revision 1.73 2005/02/01 19:35:43 ksekar
57 Removed obsolete arguments from mDNS_SetSecretForZone
58
59 Revision 1.72 2005/02/01 01:38:53 shersche
60 Handle null DynDNS configuration more gracefully
61
62 Revision 1.71 2005/01/27 22:57:57 cheshire
63 Fix compile errors on gcc4
64
65 Revision 1.70 2005/01/25 08:12:52 shersche
66 <rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
67 Bug #: 3947417
68
69 Revision 1.69 2005/01/11 04:39:48 shersche
70 Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
71
72 Revision 1.68 2005/01/11 02:04:48 shersche
73 Gracefully handle when IPv6 is not installed on a user's machine
74
75 Revision 1.67 2004/12/18 00:51:52 cheshire
76 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
77
78 Revision 1.66 2004/12/17 23:37:49 cheshire
79 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
80 (and other repetitive configuration changes)
81
82 Revision 1.65 2004/12/15 07:34:45 shersche
83 Add platform support for IPv4 and IPv6 unicast sockets
84
85 Revision 1.64 2004/12/15 06:06:15 shersche
86 Fix problem in obtaining IPv6 subnet mask
87
88 Revision 1.63 2004/11/23 03:39:47 cheshire
89 Let interface name/index mapping capability live directly in JNISupport.c,
90 instead of having to call through to the daemon via IPC to get this information.
91
92 Revision 1.62 2004/11/12 03:16:41 rpantos
93 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
94
95 Revision 1.61 2004/11/05 22:54:38 shersche
96 Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
97 Submitted by: Pavel Repin <prepin@gmail.com>
98
99 Revision 1.60 2004/11/05 22:41:56 shersche
100 Determine subnet mask when populating network interface data structures
101 Submitted by: Pavel Repin <prepin@gmail.com>
102 Reviewed by:
103
104 Revision 1.59 2004/10/28 03:24:42 cheshire
105 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
106
107 Revision 1.58 2004/10/16 00:17:01 cheshire
108 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
109
110 Revision 1.57 2004/10/11 21:53:15 shersche
111 <rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
112 Bug #: 3832450
113
114 Revision 1.56 2004/09/26 23:20:36 ksekar
115 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
116
117 Revision 1.55 2004/09/21 21:02:57 cheshire
118 Set up ifname before calling mDNS_RegisterInterface()
119
120 Revision 1.54 2004/09/17 01:08:57 cheshire
121 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
122 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
123 declared in that file are ONLY appropriate to single-address-space embedded applications.
124 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
125
126 Revision 1.53 2004/09/17 00:19:11 cheshire
127 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
128
129 Revision 1.52 2004/09/16 00:24:50 cheshire
130 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
131
132 Revision 1.51 2004/09/14 23:42:37 cheshire
133 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
134
135 Revision 1.50 2004/08/25 23:36:56 shersche
136 <rdar://problem/3658379> Remove code that retrieves TTL from received packets
137 Bug #: 3658379
138
139 Revision 1.49 2004/08/25 16:43:29 ksekar
140 Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
141 hostname parameter.
142
143 Revision 1.48 2004/08/14 03:22:43 cheshire
144 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
145 Add GetUserSpecifiedDDNSName() routine
146 Convert ServiceRegDomain to domainname instead of C string
147 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
148
149 Revision 1.47 2004/08/06 17:33:02 shersche
150 <rdar://problem/3753797> Put correct length of string in first byte of nicelabel
151 Bug #: 3753797
152
153 Revision 1.46 2004/08/05 05:43:01 shersche
154 <rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
155 Bug #: 3751566
156
157 Revision 1.45 2004/07/26 22:49:31 ksekar
158 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
159
160 Revision 1.44 2004/07/26 05:42:50 shersche
161 use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
162
163 Revision 1.43 2004/07/13 21:24:25 rpantos
164 Fix for <rdar://problem/3701120>.
165
166 Revision 1.42 2004/06/24 15:23:24 shersche
167 Add InterfaceListChanged callback. This callback is used in Service.c to add link local routes to the routing table
168 Submitted by: herscher
169
170 Revision 1.41 2004/06/18 05:22:16 rpantos
171 Integrate Scott's changes
172
173 Revision 1.40 2004/05/26 09:06:07 bradley
174 Retry while building the interface list if it returns an error since the two-step process required to
175 get the interface list could allow a subsequent interface change to come in that window and change the
176 needed size after getting the size, but before getting the list, causing it to return an error.
177 Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
178
179 Revision 1.39 2004/05/18 23:51:27 cheshire
180 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
181
182 Revision 1.38 2004/05/13 04:57:48 ksekar
183 Removed unnecessary FreeSearchList function
184
185 Revision 1.37 2004/05/13 04:54:20 ksekar
186 Unified list copy/free code. Added symetric list for
187
188 Revision 1.36 2004/05/12 22:03:09 ksekar
189 Made GetSearchDomainList a true platform-layer call (declaration moved
190 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
191 only on non-OSX platforms. Changed call to return a copy of the list
192 to avoid shared memory issues. Added a routine to free the list.
193
194 Revision 1.35 2004/04/21 02:49:12 cheshire
195 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
196
197 Revision 1.34 2004/04/15 01:00:05 bradley
198 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
199 without .local name resolving support will need to manually query for A/AAAA records as needed.
200
201 Revision 1.33 2004/04/14 23:09:29 ksekar
202 Support for TSIG signed dynamic updates.
203
204 Revision 1.32 2004/04/09 17:40:26 cheshire
205 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
206
207 Revision 1.31 2004/04/09 00:40:46 bradley
208 Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
209
210 Revision 1.30 2004/04/09 00:33:58 bradley
211 Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
212
213 Revision 1.29 2004/03/15 02:07:46 bradley
214 Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
215 handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
216 does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
217
218 Revision 1.28 2004/03/07 00:26:39 bradley
219 Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
220 Added count assert when building the wait list to catch underruns/overruns if the code is changed.
221
222 Revision 1.27 2004/01/30 02:44:32 bradley
223 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
224 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
225 are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
226 (it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
227 software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
228 reporting HINFO records with the Windows and mDNSResponder version information.
229
230 Revision 1.26 2004/01/24 04:59:16 cheshire
231 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
232
233 Revision 1.25 2003/11/14 20:59:09 cheshire
234 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
235 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
236
237 Revision 1.24 2003/10/24 23:23:02 bradley
238 Removed legacy port 53 support as it is no longer needed.
239
240 Revision 1.23 2003/10/14 03:26:12 bradley
241 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
242
243 Revision 1.22 2003/08/20 06:21:25 bradley
244 Updated to latest internal version of the mDNSWindows platform layer: Added support
245 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
246 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
247 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
248 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
249 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
250 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
251 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
252 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
253
254 Revision 1.21 2003/08/18 23:09:57 cheshire
255 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
256
257 Revision 1.20 2003/08/12 19:56:27 cheshire
258 Update to APSL 2.0
259
260 Revision 1.19 2003/08/05 23:58:18 cheshire
261 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
262 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
263
264 Revision 1.18 2003/07/23 21:16:30 cheshire
265 Removed a couple of debugfs
266
267 Revision 1.17 2003/07/23 02:23:01 cheshire
268 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
269 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
270
271 Revision 1.16 2003/07/19 03:15:16 cheshire
272 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
273 and add the obvious trivial implementations to each platform support layer
274
275 Revision 1.15 2003/07/02 21:20:04 cheshire
276 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
277
278 Revision 1.14 2003/05/26 03:21:30 cheshire
279 Tidy up address structure naming:
280 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
281 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
282 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
283
284 Revision 1.13 2003/05/26 03:01:28 cheshire
285 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
286
287 Revision 1.12 2003/05/06 21:06:05 cheshire
288 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
289
290 Revision 1.11 2003/05/06 00:00:51 cheshire
291 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
292
293 Revision 1.10 2003/04/29 00:06:09 cheshire
294 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
295
296 Revision 1.9 2003/04/26 02:40:01 cheshire
297 Add void LogMsg( const char *format, ... )
298
299 Revision 1.8 2003/03/22 02:57:44 cheshire
300 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
301
302 Revision 1.7 2003/03/15 04:40:38 cheshire
303 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
304
305 Revision 1.6 2003/02/21 01:54:10 cheshire
306 <rdar://problem/3099194> mDNSResponder needs performance improvements
307 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
308
309 Revision 1.5 2003/02/20 00:59:03 cheshire
310 Brought Windows code up to date so it complies with
311 Josh Graessley's interface changes for IPv6 support.
312 (Actual support for IPv6 on Windows will come later.)
313
314 Revision 1.4 2002/09/21 20:44:54 zarzycki
315 Added APSL info
316
317 Revision 1.3 2002/09/20 05:50:45 bradley
318 Multicast DNS platform plugin for Win32
319
320 To Do:
321
322 - Get unicode name of machine for nice name instead of just the host name.
323 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
324 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
325 - Implement TCP support for truncated packets (only stubs now).
326 */
327
328 #include <stdarg.h>
329 #include <stddef.h>
330 #include <stdio.h>
331 #include <stdlib.h>
332 #include <string.h>
333
334 #include "CommonServices.h"
335 #include "DebugServices.h"
336 #include "RegNames.h"
337 #include <dns_sd.h>
338
339 #include <Iphlpapi.h>
340 #if( !TARGET_OS_WINDOWS_CE )
341 #include <mswsock.h>
342 #include <process.h>
343 #include <ntsecapi.h>
344 #endif
345
346 #include "mDNSEmbeddedAPI.h"
347
348 #include "mDNSWin32.h"
349
350 #if 0
351 #pragma mark == Constants ==
352 #endif
353
354 //===========================================================================================================================
355 // Constants
356 //===========================================================================================================================
357
358 #define DEBUG_NAME "[mDNSWin32] "
359
360 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
361 #define MDNS_WINDOWS_ENABLE_IPV4 1
362 #define MDNS_WINDOWS_ENABLE_IPV6 1
363 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
364
365 #define kMDNSDefaultName "My Computer"
366
367 #define kWinSockMajorMin 2
368 #define kWinSockMinorMin 2
369
370 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
371 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
372 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
373 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 )
374 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 )
375 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 )
376 #define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
377
378 #define kRegistryMaxKeyLength 255
379
380 #if( !TARGET_OS_WINDOWS_CE )
381 static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
382 #endif
383
384
385 #if 0
386 #pragma mark == Prototypes ==
387 #endif
388
389 //===========================================================================================================================
390 // Prototypes
391 //===========================================================================================================================
392
393 mDNSlocal mStatus SetupSynchronizationObjects( mDNS * const inMDNS );
394 mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS );
395 mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS );
396 mDNSlocal mStatus SetupHostName( mDNS * const inMDNS );
397 mDNSlocal mStatus SetupName( mDNS * const inMDNS );
398 mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS );
399 mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS );
400 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
401 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
402 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef );
403 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
404 mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS );
405 mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS );
406
407 mDNSlocal mStatus SetupThread( mDNS * const inMDNS );
408 mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS );
409 mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam );
410 mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS );
411 mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
412 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock );
413 mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
414 mDNSlocal void ProcessingThreadComputerDescriptionChanged( mDNS * inMDNS );
415 mDNSlocal void ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS );
416 mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS * inMDNS );
417
418
419 // Platform Accessors
420
421 #ifdef __cplusplus
422 extern "C" {
423 #endif
424
425 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
426 struct mDNSPlatformInterfaceInfo
427 {
428 const char * name;
429 mDNSAddr ip;
430 };
431
432 typedef struct mDNSTCPConnectionData mDNSTCPConnectionData;
433 struct mDNSTCPConnectionData
434 {
435 SocketRef sock;
436 BOOL connected;
437 TCPConnectionCallback callback;
438 void * context;
439 HANDLE pendingEvent;
440 mDNSTCPConnectionData * next;
441 };
442
443
444 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
445 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
446
447 // Utilities
448
449 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
450 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
451 #endif
452
453 #if( !TARGET_OS_WINDOWS_CE )
454 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
455 #endif
456
457 #if( TARGET_OS_WINDOWS_CE )
458 mDNSlocal int getifaddrs_ce( struct ifaddrs **outAddrs );
459 #endif
460
461 mDNSlocal mDNSBool CanReceiveUnicast( void );
462
463 mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string );
464 mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
465 mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh);
466 mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
467 mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
468 mDNSlocal OSStatus ConvertUTF8ToLsaString( const char * input, PLSA_UNICODE_STRING output );
469 mDNSlocal OSStatus ConvertLsaStringToUTF8( PLSA_UNICODE_STRING input, char ** output );
470 mDNSlocal void FreeTCPConnectionData( mDNSTCPConnectionData * data );
471
472 #ifdef __cplusplus
473 }
474 #endif
475
476 #if 0
477 #pragma mark == Globals ==
478 #endif
479
480 //===========================================================================================================================
481 // Globals
482 //===========================================================================================================================
483
484 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
485 mDNSs32 mDNSPlatformOneSecond = 0;
486 mDNSlocal mDNSTCPConnectionData * gTCPConnectionList = NULL;
487 mDNSlocal int gTCPConnections = 0;
488 mDNSlocal BOOL gWaitListChanged = FALSE;
489
490 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
491
492 typedef DWORD
493 ( WINAPI * GetAdaptersAddressesFunctionPtr )(
494 ULONG inFamily,
495 DWORD inFlags,
496 PVOID inReserved,
497 PIP_ADAPTER_ADDRESSES inAdapter,
498 PULONG outBufferSize );
499
500 mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
501 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
502
503 #endif
504
505 #if 0
506 #pragma mark -
507 #pragma mark == Platform Support ==
508 #endif
509
510 //===========================================================================================================================
511 // mDNSPlatformInit
512 //===========================================================================================================================
513
514 mStatus mDNSPlatformInit( mDNS * const inMDNS )
515 {
516 mStatus err;
517 WSADATA wsaData;
518 int supported;
519 struct sockaddr_in sa4;
520 struct sockaddr_in6 sa6;
521 int sa4len;
522 int sa6len;
523
524 dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
525
526 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
527 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
528
529 memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
530 if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
531 inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
532 mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
533
534 // Startup WinSock 2.2 or later.
535
536 err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
537 require_noerr( err, exit );
538
539 supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
540 require_action( supported, exit, err = mStatus_UnsupportedErr );
541
542 inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
543
544 // Setup the HINFO HW/SW strings.
545
546 err = GetWindowsVersionString( (char *) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2 );
547 check_noerr( err );
548 inMDNS->HIHardware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
549 dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
550
551 mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
552 "mDNSResponder (%s %s)", __DATE__, __TIME__ );
553 inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
554 dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
555
556 // Set up the IPv4 unicast socket
557
558 inMDNS->p->unicastSock4 = INVALID_SOCKET;
559 inMDNS->p->unicastSock4ReadEvent = NULL;
560 inMDNS->p->unicastSock4RecvMsgPtr = NULL;
561
562 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
563
564 sa4.sin_family = AF_INET;
565 sa4.sin_addr.s_addr = INADDR_ANY;
566 err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4 );
567 check_noerr( err );
568 sa4len = sizeof( sa4 );
569 err = getsockname( inMDNS->p->unicastSock4, (struct sockaddr*) &sa4, &sa4len );
570 require_noerr( err, exit );
571 inMDNS->UnicastPort4.NotAnInteger = sa4.sin_port;
572 inMDNS->p->unicastSock4ReadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
573 err = translate_errno( inMDNS->p->unicastSock4ReadEvent, (mStatus) GetLastError(), kUnknownErr );
574 require_noerr( err, exit );
575 err = WSAEventSelect( inMDNS->p->unicastSock4, inMDNS->p->unicastSock4ReadEvent, FD_READ );
576 require_noerr( err, exit );
577 #if( !TARGET_OS_WINDOWS_CE )
578 {
579 DWORD size;
580
581 err = WSAIoctl( inMDNS->p->unicastSock4, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID,
582 sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4RecvMsgPtr, sizeof( inMDNS->p->unicastSock4RecvMsgPtr ), &size, NULL, NULL );
583
584 if ( err != 0 )
585 {
586 inMDNS->p->unicastSock4RecvMsgPtr = NULL;
587 }
588 }
589 #endif
590
591 #endif
592
593 // Set up the IPv6 unicast socket
594
595 inMDNS->p->unicastSock6 = INVALID_SOCKET;
596 inMDNS->p->unicastSock6ReadEvent = NULL;
597 inMDNS->p->unicastSock6RecvMsgPtr = NULL;
598
599 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
600
601 sa6.sin6_family = AF_INET6;
602 sa6.sin6_addr = in6addr_any;
603 sa6.sin6_scope_id = 0;
604
605 // This call will fail if the machine hasn't installed IPv6. In that case,
606 // the error will be WSAEAFNOSUPPORT.
607
608 err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6 );
609 require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
610 inMDNS->p->unicastSock6ReadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
611 err = translate_errno( inMDNS->p->unicastSock6ReadEvent, (mStatus) GetLastError(), kUnknownErr );
612 require_noerr( err, exit );
613
614 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
615
616 if ( inMDNS->p->unicastSock6 != INVALID_SOCKET )
617 {
618 sa6len = sizeof( sa6 );
619 err = getsockname( inMDNS->p->unicastSock6, (struct sockaddr*) &sa6, &sa6len );
620 require_noerr( err, exit );
621 inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port;
622
623 err = WSAEventSelect( inMDNS->p->unicastSock6, inMDNS->p->unicastSock6ReadEvent, FD_READ );
624 require_noerr( err, exit );
625
626 #if( !TARGET_OS_WINDOWS_CE )
627 {
628 DWORD size;
629
630 err = WSAIoctl( inMDNS->p->unicastSock6, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID,
631 sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6RecvMsgPtr, sizeof( inMDNS->p->unicastSock6RecvMsgPtr ), &size, NULL, NULL );
632
633 if ( err != 0 )
634 {
635 inMDNS->p->unicastSock6RecvMsgPtr = NULL;
636 }
637 }
638 #endif
639 }
640
641 #endif
642
643 // Set up the mDNS thread.
644
645 err = SetupSynchronizationObjects( inMDNS );
646 require_noerr( err, exit );
647
648 err = SetupThread( inMDNS );
649 require_noerr( err, exit );
650
651 // Success!
652
653 mDNSCoreInitComplete( inMDNS, err );
654
655 exit:
656 if( err )
657 {
658 mDNSPlatformClose( inMDNS );
659 }
660 dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
661 return( err );
662 }
663
664 //===========================================================================================================================
665 // mDNSPlatformClose
666 //===========================================================================================================================
667
668 void mDNSPlatformClose( mDNS * const inMDNS )
669 {
670 mStatus err;
671
672 dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
673 check( inMDNS );
674
675 // Tear everything down in reverse order to how it was set up.
676
677 err = TearDownThread( inMDNS );
678 check_noerr( err );
679
680 err = TearDownInterfaceList( inMDNS );
681 check_noerr( err );
682 check( !inMDNS->p->inactiveInterfaceList );
683
684 err = TearDownSynchronizationObjects( inMDNS );
685 check_noerr( err );
686
687 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
688
689 if ( inMDNS->p->unicastSock4ReadEvent )
690 {
691 CloseHandle( inMDNS->p->unicastSock4ReadEvent );
692 inMDNS->p->unicastSock4ReadEvent = 0;
693 }
694
695 if ( IsValidSocket( inMDNS->p->unicastSock4 ) )
696 {
697 close_compat( inMDNS->p->unicastSock4 );
698 }
699
700 #endif
701
702 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
703
704 if ( inMDNS->p->unicastSock6ReadEvent )
705 {
706 CloseHandle( inMDNS->p->unicastSock6ReadEvent );
707 inMDNS->p->unicastSock6ReadEvent = 0;
708 }
709
710 if ( IsValidSocket( inMDNS->p->unicastSock6 ) )
711 {
712 close_compat( inMDNS->p->unicastSock6 );
713 }
714
715 #endif
716
717 // Free the DLL needed for IPv6 support.
718
719 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
720 if( gIPHelperLibraryInstance )
721 {
722 gGetAdaptersAddressesFunctionPtr = NULL;
723
724 FreeLibrary( gIPHelperLibraryInstance );
725 gIPHelperLibraryInstance = NULL;
726 }
727 #endif
728
729 WSACleanup();
730
731 dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
732 }
733
734 //===========================================================================================================================
735 // mDNSPlatformSendUDP
736 //===========================================================================================================================
737
738 mStatus
739 mDNSPlatformSendUDP(
740 const mDNS * const inMDNS,
741 const void * const inMsg,
742 const mDNSu8 * const inMsgEnd,
743 mDNSInterfaceID inInterfaceID,
744 const mDNSAddr * inDstIP,
745 mDNSIPPort inDstPort )
746 {
747 SOCKET sendingsocket = INVALID_SOCKET;
748 mStatus err = mStatus_NoError;
749 mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID;
750 struct sockaddr_storage addr;
751 int n;
752
753 DEBUG_USE_ONLY( inMDNS );
754
755 n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
756 check( inMDNS );
757 check( inMsg );
758 check( inMsgEnd );
759 check( inDstIP );
760
761 dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
762
763 if( inDstIP->type == mDNSAddrType_IPv4 )
764 {
765 struct sockaddr_in * sa4;
766
767 sa4 = (struct sockaddr_in *) &addr;
768 sa4->sin_family = AF_INET;
769 sa4->sin_port = inDstPort.NotAnInteger;
770 sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
771 sendingsocket = ifd ? ifd->sock : inMDNS->p->unicastSock4;
772 }
773 else if( inDstIP->type == mDNSAddrType_IPv6 )
774 {
775 struct sockaddr_in6 * sa6;
776
777 sa6 = (struct sockaddr_in6 *) &addr;
778 sa6->sin6_family = AF_INET6;
779 sa6->sin6_port = inDstPort.NotAnInteger;
780 sa6->sin6_flowinfo = 0;
781 sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
782 sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
783 sendingsocket = ifd ? ifd->sock : inMDNS->p->unicastSock6;
784 }
785 else
786 {
787 dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
788 err = mStatus_BadParamErr;
789 goto exit;
790 }
791
792 if (IsValidSocket(sendingsocket))
793 {
794 n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
795 err = translate_errno( n > 0, errno_compat(), kWriteErr );
796 require_noerr( err, exit );
797 }
798
799 exit:
800 return( err );
801 }
802
803 //===========================================================================================================================
804 // mDNSPlatformLock
805 //===========================================================================================================================
806
807 void mDNSPlatformLock( const mDNS * const inMDNS )
808 {
809 check( inMDNS );
810
811 if ( inMDNS->p->lockInitialized )
812 {
813 EnterCriticalSection( &inMDNS->p->lock );
814 }
815 }
816
817 //===========================================================================================================================
818 // mDNSPlatformUnlock
819 //===========================================================================================================================
820
821 void mDNSPlatformUnlock( const mDNS * const inMDNS )
822 {
823 check( inMDNS );
824 check( inMDNS->p );
825
826 if ( inMDNS->p->lockInitialized )
827 {
828 check( inMDNS->p->threadID );
829
830 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
831 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
832
833 if( GetCurrentThreadId() != inMDNS->p->threadID )
834 {
835 BOOL wasSet;
836
837 wasSet = SetEvent( inMDNS->p->wakeupEvent );
838 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
839 }
840 LeaveCriticalSection( &inMDNS->p->lock );
841 }
842 }
843
844 //===========================================================================================================================
845 // mDNSPlatformStrCopy
846 //===========================================================================================================================
847
848 void mDNSPlatformStrCopy( const void *inSrc, void *inDst )
849 {
850 check( inSrc );
851 check( inDst );
852
853 strcpy( (char *) inDst, (const char*) inSrc );
854 }
855
856 //===========================================================================================================================
857 // mDNSPlatformStrLen
858 //===========================================================================================================================
859
860 mDNSu32 mDNSPlatformStrLen( const void *inSrc )
861 {
862 check( inSrc );
863
864 return( (mDNSu32) strlen( (const char *) inSrc ) );
865 }
866
867 //===========================================================================================================================
868 // mDNSPlatformMemCopy
869 //===========================================================================================================================
870
871 void mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
872 {
873 check( inSrc );
874 check( inDst );
875
876 memcpy( inDst, inSrc, inSize );
877 }
878
879 //===========================================================================================================================
880 // mDNSPlatformMemSame
881 //===========================================================================================================================
882
883 mDNSBool mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
884 {
885 check( inSrc );
886 check( inDst );
887
888 return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
889 }
890
891 //===========================================================================================================================
892 // mDNSPlatformMemZero
893 //===========================================================================================================================
894
895 void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
896 {
897 check( inDst );
898
899 memset( inDst, 0, inSize );
900 }
901
902 //===========================================================================================================================
903 // mDNSPlatformMemAllocate
904 //===========================================================================================================================
905
906 mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
907 {
908 void * mem;
909
910 check( inSize > 0 );
911
912 mem = malloc( inSize );
913 check( mem );
914
915 return( mem );
916 }
917
918 //===========================================================================================================================
919 // mDNSPlatformMemFree
920 //===========================================================================================================================
921
922 mDNSexport void mDNSPlatformMemFree( void *inMem )
923 {
924 check( inMem );
925
926 free( inMem );
927 }
928
929 //===========================================================================================================================
930 // mDNSPlatformRandomSeed
931 //===========================================================================================================================
932
933 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
934 {
935 return( GetTickCount() );
936 }
937
938 //===========================================================================================================================
939 // mDNSPlatformTimeInit
940 //===========================================================================================================================
941
942 mDNSexport mStatus mDNSPlatformTimeInit( void )
943 {
944 // No special setup is required on Windows -- we just use GetTickCount().
945 return( mStatus_NoError );
946 }
947
948 //===========================================================================================================================
949 // mDNSPlatformRawTime
950 //===========================================================================================================================
951
952 mDNSs32 mDNSPlatformRawTime( void )
953 {
954 return( (mDNSs32) GetTickCount() );
955 }
956
957 //===========================================================================================================================
958 // mDNSPlatformUTC
959 //===========================================================================================================================
960
961 mDNSexport mDNSs32 mDNSPlatformUTC( void )
962 {
963 return( -1 );
964 }
965
966 //===========================================================================================================================
967 // mDNSPlatformInterfaceNameToID
968 //===========================================================================================================================
969
970 mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
971 {
972 mStatus err;
973 mDNSInterfaceData * ifd;
974
975 check( inMDNS );
976 check( inMDNS->p );
977 check( inName );
978
979 // Search for an interface with the specified name,
980
981 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
982 {
983 if( strcmp( ifd->name, inName ) == 0 )
984 {
985 break;
986 }
987 }
988 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
989
990 // Success!
991
992 if( outID )
993 {
994 *outID = (mDNSInterfaceID) ifd;
995 }
996 err = mStatus_NoError;
997
998 exit:
999 return( err );
1000 }
1001
1002 //===========================================================================================================================
1003 // mDNSPlatformInterfaceIDToInfo
1004 //===========================================================================================================================
1005
1006 mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
1007 {
1008 mStatus err;
1009 mDNSInterfaceData * ifd;
1010
1011 check( inMDNS );
1012 check( inID );
1013 check( outInfo );
1014
1015 // Search for an interface with the specified ID,
1016
1017 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
1018 {
1019 if( ifd == (mDNSInterfaceData *) inID )
1020 {
1021 break;
1022 }
1023 }
1024 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
1025
1026 // Success!
1027
1028 outInfo->name = ifd->name;
1029 outInfo->ip = ifd->interfaceInfo.ip;
1030 err = mStatus_NoError;
1031
1032 exit:
1033 return( err );
1034 }
1035
1036 //===========================================================================================================================
1037 // mDNSPlatformInterfaceIDfromInterfaceIndex
1038 //===========================================================================================================================
1039
1040 mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const inMDNS, mDNSu32 inIndex )
1041 {
1042 mDNSInterfaceID id;
1043
1044 id = mDNSNULL;
1045 if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
1046 {
1047 id = mDNSInterface_LocalOnly;
1048 }
1049 else if( inIndex != 0 )
1050 {
1051 mDNSInterfaceData * ifd;
1052
1053 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
1054 {
1055 if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
1056 {
1057 id = ifd->interfaceInfo.InterfaceID;
1058 break;
1059 }
1060 }
1061 check( ifd );
1062 }
1063 return( id );
1064 }
1065
1066 //===========================================================================================================================
1067 // mDNSPlatformInterfaceIndexfromInterfaceID
1068 //===========================================================================================================================
1069
1070 mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mDNSInterfaceID inID )
1071 {
1072 mDNSu32 index;
1073
1074 index = 0;
1075 if( inID == mDNSInterface_LocalOnly )
1076 {
1077 index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
1078 }
1079 else if( inID )
1080 {
1081 mDNSInterfaceData * ifd;
1082
1083 // Search active interfaces.
1084 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
1085 {
1086 if( (mDNSInterfaceID) ifd == inID )
1087 {
1088 index = ifd->scopeID;
1089 break;
1090 }
1091 }
1092
1093 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
1094
1095 if( !ifd )
1096 {
1097 for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
1098 {
1099 if( (mDNSInterfaceID) ifd == inID )
1100 {
1101 index = ifd->scopeID;
1102 break;
1103 }
1104 }
1105 }
1106 check( ifd );
1107 }
1108 return( index );
1109 }
1110
1111 //===========================================================================================================================
1112 // mDNSPlatformTCPConnect
1113 //===========================================================================================================================
1114
1115 mStatus
1116 mDNSPlatformTCPConnect(
1117 const mDNSAddr * inDstIP,
1118 mDNSOpaque16 inDstPort,
1119 mDNSInterfaceID inInterfaceID,
1120 TCPConnectionCallback inCallback,
1121 void * inContext,
1122 int * outSock )
1123 {
1124 u_long on = 1; // "on" for setsockopt
1125 struct sockaddr_in saddr;
1126 mDNSTCPConnectionData * tcd = NULL;
1127 mStatus err = mStatus_NoError;
1128
1129 DEBUG_UNUSED( inInterfaceID );
1130
1131 *outSock = INVALID_SOCKET;
1132
1133 if ( inDstIP->type != mDNSAddrType_IPv4 )
1134 {
1135 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1136 return mStatus_UnknownErr;
1137 }
1138
1139 // Setup connection data object
1140
1141 tcd = (mDNSTCPConnectionData*) malloc( sizeof( mDNSTCPConnectionData ) );
1142 require_action( tcd, exit, err = mStatus_NoMemoryErr );
1143 memset( tcd, 0, sizeof( mDNSTCPConnectionData ) );
1144
1145 tcd->sock = INVALID_SOCKET;
1146 tcd->callback = inCallback;
1147 tcd->context = inContext;
1148
1149 bzero(&saddr, sizeof(saddr));
1150 saddr.sin_family = AF_INET;
1151 saddr.sin_port = inDstPort.NotAnInteger;
1152 memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
1153
1154 // Create the socket
1155
1156 tcd->sock = socket(AF_INET, SOCK_STREAM, 0);
1157 err = translate_errno( tcd->sock != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
1158 require_noerr( err, exit );
1159
1160 // Set it to be non-blocking
1161
1162 err = ioctlsocket( tcd->sock, FIONBIO, &on );
1163 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
1164 require_noerr( err, exit );
1165
1166 // Try and do connect
1167
1168 err = connect( tcd->sock, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
1169 require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
1170 tcd->connected = !err ? TRUE : FALSE;
1171 tcd->pendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1172 err = translate_errno( tcd->pendingEvent, GetLastError(), mStatus_UnknownErr );
1173 require_noerr( err, exit );
1174 err = WSAEventSelect( tcd->sock, tcd->pendingEvent, FD_CONNECT|FD_READ|FD_CLOSE );
1175 require_noerr( err, exit );
1176
1177 // Bookkeeping
1178
1179 tcd->next = gTCPConnectionList;
1180 gTCPConnectionList = tcd;
1181 gTCPConnections++;
1182 gWaitListChanged = TRUE;
1183
1184 *outSock = (int) tcd->sock;
1185
1186 exit:
1187
1188 if ( !err )
1189 {
1190 err = tcd->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
1191 }
1192 else if ( tcd )
1193 {
1194 FreeTCPConnectionData( tcd );
1195 }
1196
1197 return err;
1198 }
1199
1200 //===========================================================================================================================
1201 // mDNSPlatformTCPCloseConnection
1202 //===========================================================================================================================
1203
1204 void mDNSPlatformTCPCloseConnection( int inSock )
1205 {
1206 mDNSTCPConnectionData * tcd = gTCPConnectionList;
1207 mDNSTCPConnectionData * last = NULL;
1208
1209 while ( tcd )
1210 {
1211 if ( tcd->sock == ( SOCKET ) inSock )
1212 {
1213 if ( last == NULL )
1214 {
1215 gTCPConnectionList = tcd->next;
1216 }
1217 else
1218 {
1219 last->next = tcd->next;
1220 }
1221
1222 FreeTCPConnectionData( tcd );
1223
1224 gTCPConnections--;
1225 gWaitListChanged = TRUE;
1226
1227 break;
1228 }
1229
1230 last = tcd;
1231 tcd = tcd->next;
1232 }
1233 }
1234
1235 //===========================================================================================================================
1236 // mDNSPlatformReadTCP
1237 //===========================================================================================================================
1238
1239 int mDNSPlatformReadTCP( int inSock, void *inBuffer, int inBufferSize )
1240 {
1241 int nread;
1242 OSStatus err;
1243
1244 nread = recv( inSock, inBuffer, inBufferSize, 0);
1245 err = translate_errno( ( nread >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
1246 require_noerr( err, exit );
1247
1248 if ( nread < 0 )
1249 {
1250 nread = 0;
1251 }
1252
1253 exit:
1254
1255 return nread;
1256 }
1257
1258 //===========================================================================================================================
1259 // mDNSPlatformWriteTCP
1260 //===========================================================================================================================
1261
1262 int mDNSPlatformWriteTCP( int inSock, const char *inMsg, int inMsgSize )
1263 {
1264 int nsent;
1265 OSStatus err;
1266
1267 nsent = send( inSock, inMsg, inMsgSize, 0 );
1268
1269 err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
1270 require_noerr( err, exit );
1271
1272 if ( nsent < 0)
1273 {
1274 nsent = 0;
1275 }
1276
1277 exit:
1278
1279 return nsent;
1280 }
1281
1282 //===========================================================================================================================
1283 // dDNSPlatformGetConfig
1284 //===========================================================================================================================
1285
1286 void
1287 dDNSPlatformGetConfig(domainname * const fqdn, domainname *const regDomain, DNameListElem ** browseDomains)
1288 {
1289 LPSTR name = NULL;
1290 char subKeyName[kRegistryMaxKeyLength + 1];
1291 DWORD cSubKeys = 0;
1292 DWORD cbMaxSubKey;
1293 DWORD cchMaxClass;
1294 DWORD dwSize;
1295 DWORD enabled;
1296 HKEY key;
1297 HKEY subKey = NULL;
1298 domainname dname;
1299 DWORD i;
1300 OSStatus err;
1301
1302 // Initialize
1303
1304 fqdn->c[0] = regDomain->c[0] = '\0';
1305
1306 *browseDomains = NULL;
1307
1308 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
1309 require_noerr( err, exit );
1310
1311 err = RegQueryString( key, "", &name, &dwSize, &enabled );
1312 if ( !err && ( name[0] != '\0' ) && enabled )
1313 {
1314 if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
1315 {
1316 dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
1317 }
1318 }
1319
1320 if ( key )
1321 {
1322 RegCloseKey( key );
1323 key = NULL;
1324 }
1325
1326 if ( name )
1327 {
1328 free( name );
1329 name = NULL;
1330 }
1331
1332 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains, &key );
1333 require_noerr( err, exit );
1334
1335 // Get information about this node
1336
1337 err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
1338 require_noerr( err, exit );
1339
1340 for ( i = 0; i < cSubKeys; i++)
1341 {
1342 DWORD enabled;
1343
1344 dwSize = kRegistryMaxKeyLength;
1345
1346 err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
1347
1348 if ( !err )
1349 {
1350 err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
1351 require_noerr( err, exit );
1352
1353 dwSize = sizeof( DWORD );
1354 err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
1355
1356 if ( !err && ( subKeyName[0] != '\0' ) && enabled )
1357 {
1358 if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
1359 {
1360 dlog( kDebugLevelError, "bad DDNS browse domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
1361 }
1362 else
1363 {
1364 DNameListElem * browseDomain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
1365 require_action( browseDomain, exit, err = mStatus_NoMemoryErr );
1366
1367 AssignDomainName(&browseDomain->name, &dname);
1368 browseDomain->next = *browseDomains;
1369
1370 *browseDomains = browseDomain;
1371 }
1372 }
1373
1374 RegCloseKey( subKey );
1375 subKey = NULL;
1376 }
1377 }
1378
1379 if ( key )
1380 {
1381 RegCloseKey( key );
1382 key = NULL;
1383 }
1384
1385 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName TEXT("\\Parameters\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains, &key );
1386 require_noerr( err, exit );
1387
1388 err = RegQueryString( key, "", &name, &dwSize, &enabled );
1389 if ( !err && ( name[0] != '\0' ) && enabled )
1390 {
1391 if ( !MakeDomainNameFromDNSNameString( regDomain, name ) || !regDomain->c[0] )
1392 {
1393 dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)");
1394 }
1395 }
1396
1397 exit:
1398
1399 if ( subKey )
1400 {
1401 RegCloseKey( subKey );
1402 }
1403
1404 if ( key )
1405 {
1406 RegCloseKey( key );
1407 }
1408
1409 if ( name )
1410 {
1411 free( name );
1412 }
1413 }
1414
1415
1416 //===========================================================================================================================
1417 // dDNSPlatformSetNameStatus
1418 //===========================================================================================================================
1419
1420 void
1421 dDNSPlatformSetNameStatus(domainname *const dname, mStatus status)
1422 {
1423 char uname[MAX_ESCAPED_DOMAIN_NAME];
1424 LPCTSTR name;
1425 HKEY key = NULL;
1426 mStatus err;
1427 char * p;
1428
1429 ConvertDomainNameToCString(dname, uname);
1430
1431 p = uname;
1432
1433 while (*p)
1434 {
1435 *p = (char) tolower(*p);
1436 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
1437 p++;
1438 }
1439
1440 check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
1441 name = TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName TEXT("\\Parameters\\DynDNS\\State\\HostNames");
1442 err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
1443 require_noerr( err, exit );
1444
1445 status = ( status ) ? 0 : 1;
1446 err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &status, sizeof(DWORD) );
1447 require_noerr( err, exit );
1448
1449 exit:
1450
1451 if ( key )
1452 {
1453 RegCloseKey( key );
1454 }
1455
1456 return;
1457 }
1458
1459
1460 //===========================================================================================================================
1461 // dDNSPlatformSetSecretForDomain
1462 //===========================================================================================================================
1463
1464 void
1465 dDNSPlatformSetSecretForDomain( mDNS *m, const domainname * domain )
1466 {
1467 char dstring[MAX_ESCAPED_DOMAIN_NAME];
1468 domainname * d;
1469 domainname canon;
1470 size_t i;
1471 size_t dlen;
1472 LSA_OBJECT_ATTRIBUTES attrs;
1473 LSA_HANDLE handle = NULL;
1474 LSA_UNICODE_STRING keyName = { 0, 0, NULL };
1475 LSA_UNICODE_STRING * secret = NULL;
1476 char * converted = NULL;
1477 NTSTATUS res;
1478 OSStatus err;
1479
1480 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
1481
1482 ConvertDomainNameToCString(domain, dstring);
1483 dlen = strlen(dstring);
1484 for (i = 0; i < dlen; i++)
1485 {
1486 dstring[i] = (char) tolower(dstring[i]); // canonicalize -> lower case
1487 }
1488
1489 MakeDomainNameFromDNSNameString(&canon, dstring);
1490 d = &canon;
1491
1492 // attrs are reserved, so initialize to zeroes.
1493
1494 ZeroMemory(&attrs, sizeof( attrs ) );
1495
1496 // Get a handle to the Policy object on the local system
1497
1498 res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle );
1499 err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
1500 require_noerr( err, exit );
1501
1502 // Get the encrypted data
1503
1504 err = ConvertUTF8ToLsaString( dstring, &keyName );
1505 require_noerr( err, exit );
1506
1507 res = LsaRetrievePrivateData( handle, &keyName, &secret );
1508 err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
1509 require_noerr_quiet( err, exit );
1510
1511 // Convert the unicode to string to 8 bit
1512
1513 err = ConvertLsaStringToUTF8( secret, &converted );
1514 require_noerr( err, exit );
1515
1516 mDNS_SetSecretForZone( m, d, d, converted );
1517
1518 exit:
1519
1520 if ( converted )
1521 {
1522 free( converted );
1523 converted = NULL;
1524 }
1525
1526 if ( secret )
1527 {
1528 LsaFreeMemory( secret );
1529 secret = NULL;
1530 }
1531
1532 if ( keyName.Buffer )
1533 {
1534 free( keyName.Buffer );
1535 keyName.Buffer = NULL;
1536 }
1537
1538 if ( handle )
1539 {
1540 LsaClose( handle );
1541 handle = NULL;
1542 }
1543 }
1544
1545
1546 //===========================================================================================================================
1547 // dDNSPlatformGetSearchDomainList
1548 //===========================================================================================================================
1549
1550 DNameListElem*
1551 dDNSPlatformGetSearchDomainList( void )
1552 {
1553 char * searchList = NULL;
1554 DWORD searchListLen;
1555 DNameListElem * head = NULL;
1556 DNameListElem * current = NULL;
1557 char * tok;
1558 HKEY key;
1559 mStatus err;
1560
1561 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
1562 require_noerr( err, exit );
1563
1564 err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
1565 require_noerr( err, exit );
1566
1567 // Windows separates the search domains with ','
1568
1569 tok = strtok( searchList, "," );
1570 while ( tok )
1571 {
1572 domainname domain;
1573
1574 if ( MakeDomainNameFromDNSNameString( &domain, tok ) )
1575 {
1576 DNameListElem * last = current;
1577
1578 current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
1579 require_action( current, exit, err = mStatus_NoMemoryErr );
1580
1581 AssignDomainName( &current->name, &domain );
1582 current->next = NULL;
1583
1584 if ( !head )
1585 {
1586 head = current;
1587 }
1588
1589 if ( last )
1590 {
1591 last->next = current;
1592 }
1593 }
1594
1595 tok = strtok( NULL, "," );
1596 }
1597
1598 exit:
1599
1600 if ( searchList )
1601 {
1602 free( searchList );
1603 }
1604
1605 if ( key )
1606 {
1607 RegCloseKey( key );
1608 }
1609
1610 return head;
1611 }
1612
1613
1614 //===========================================================================================================================
1615 // dDNSPlatformGetReverseMapSearchDomainList
1616 //===========================================================================================================================
1617
1618 DNameListElem*
1619 dDNSPlatformGetReverseMapSearchDomainList( void )
1620 {
1621 DNameListElem * head = NULL;
1622 DNameListElem * current = NULL;
1623 struct ifaddrs * ifa;
1624 mStatus err;
1625
1626 ifa = myGetIfAddrs( 1 );
1627 while (ifa)
1628 {
1629 mDNSAddr addr;
1630
1631 if (ifa->ifa_addr->sa_family == AF_INET && !dDNS_SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
1632 {
1633 mDNSAddr netmask;
1634 domainname domain;
1635 char buffer[256];
1636
1637 if (!dDNS_SetupAddr(&netmask, ifa->ifa_netmask))
1638 {
1639 sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
1640 addr.ip.v4.b[2] & netmask.ip.v4.b[2],
1641 addr.ip.v4.b[1] & netmask.ip.v4.b[1],
1642 addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
1643
1644 if ( MakeDomainNameFromDNSNameString( &domain, buffer ) )
1645 {
1646 DNameListElem * last = current;
1647
1648 current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
1649 require_action( current, exit, err = mStatus_NoMemoryErr );
1650
1651 AssignDomainName( &current->name, &domain );
1652 current->next = NULL;
1653
1654 if ( !head )
1655 {
1656 head = current;
1657 }
1658
1659 if ( last )
1660 {
1661 last->next = current;
1662 }
1663 }
1664 }
1665 }
1666
1667 ifa = ifa->ifa_next;
1668 }
1669
1670 exit:
1671
1672 return head;
1673 }
1674
1675
1676 //===========================================================================================================================
1677 // dDNSPlatformGetDNSServers
1678 //===========================================================================================================================
1679
1680 IPAddrListElem*
1681 dDNSPlatformGetDNSServers( void )
1682 {
1683 FIXED_INFO * fixedInfo = NULL;
1684 ULONG bufLen = sizeof( FIXED_INFO );
1685 IP_ADDR_STRING * ipAddr;
1686 IPAddrListElem * head = NULL;
1687 IPAddrListElem * current = NULL;
1688 int i = 0;
1689 mStatus err;
1690
1691 while ( 1 )
1692 {
1693 if ( fixedInfo )
1694 {
1695 GlobalFree( fixedInfo );
1696 fixedInfo = NULL;
1697 }
1698
1699 fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
1700
1701 err = GetNetworkParams( fixedInfo, &bufLen );
1702
1703 if ( ( err != ERROR_BUFFER_OVERFLOW ) || ( i++ == 100 ) )
1704 {
1705 break;
1706 }
1707 }
1708
1709 require_noerr( err, exit );
1710
1711 for ( ipAddr = &fixedInfo->DnsServerList; ipAddr; ipAddr = ipAddr->Next )
1712 {
1713 mDNSAddr addr;
1714 IPAddrListElem * last = current;
1715
1716 err = StringToAddress( &addr, ipAddr->IpAddress.String );
1717
1718 if ( err )
1719 {
1720 continue;
1721 }
1722
1723 current = (IPAddrListElem*) malloc( sizeof( IPAddrListElem ) );
1724 require_action( current, exit, err = mStatus_NoMemoryErr );
1725
1726 memcpy( &current->addr, &addr, sizeof( mDNSAddr ) );
1727 current->next = NULL;
1728
1729 if ( !head )
1730 {
1731 head = current;
1732 }
1733
1734 if ( last )
1735 {
1736 last->next = current;
1737 }
1738 }
1739
1740 exit:
1741
1742 if ( fixedInfo )
1743 {
1744 GlobalFree( fixedInfo );
1745 }
1746
1747 return head;
1748 }
1749
1750
1751 //===========================================================================================================================
1752 // dDNSPlatformGetDomainName
1753 //===========================================================================================================================
1754
1755 DNameListElem*
1756 dDNSPlatformGetDomainName( void )
1757 {
1758 FIXED_INFO * fixedInfo = NULL;
1759 ULONG bufLen = sizeof( FIXED_INFO );
1760 DNameListElem * head = NULL;
1761 int i = 0;
1762 mStatus err;
1763
1764 while ( 1 )
1765 {
1766 if ( fixedInfo )
1767 {
1768 GlobalFree( fixedInfo );
1769 fixedInfo = NULL;
1770 }
1771
1772 fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
1773
1774 err = GetNetworkParams( fixedInfo, &bufLen );
1775
1776 if ( ( err != ERROR_BUFFER_OVERFLOW ) || ( i++ == 100 ) )
1777 {
1778 break;
1779 }
1780 }
1781
1782 require_noerr( err, exit );
1783
1784 if ( fixedInfo->DomainName )
1785 {
1786 domainname dname;
1787
1788 if ( MakeDomainNameFromDNSNameString( &dname, fixedInfo->DomainName ) || !dname.c[0] )
1789 {
1790 head = (DNameListElem*) malloc( sizeof( DNameListElem ) );
1791 require_action( head, exit, err = mStatus_NoMemoryErr );
1792
1793 AssignDomainName( &head->name, &dname );
1794 head->next = NULL;
1795 }
1796 else
1797 {
1798 dlog( kDebugLevelError, "bad DDNS host name from domain name: %s", fixedInfo->DomainName );
1799 }
1800 }
1801
1802 exit:
1803
1804 if ( fixedInfo )
1805 {
1806 GlobalFree( fixedInfo );
1807 }
1808
1809 return head;
1810 }
1811
1812
1813 //===========================================================================================================================
1814 // dDNSPlatformRegisterSplitDNS
1815 //===========================================================================================================================
1816
1817 mStatus
1818 dDNSPlatformRegisterSplitDNS( mDNS * m )
1819 {
1820 DEBUG_UNUSED( m );
1821
1822 return mStatus_UnsupportedErr;
1823 }
1824
1825
1826 //===========================================================================================================================
1827 // dDNSPlatformGetPrimaryInterface
1828 //===========================================================================================================================
1829
1830 mStatus
1831 dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router )
1832 {
1833 IP_ADAPTER_INFO * pAdapterInfo = NULL;
1834 IP_ADAPTER_INFO * pAdapter;
1835 DWORD bufLen = sizeof( IP_ADAPTER_INFO );
1836 int i;
1837 BOOL found;
1838 mStatus err = mStatus_NoError;
1839
1840 DEBUG_UNUSED( m );
1841
1842 pAdapterInfo = NULL;
1843 found = FALSE;
1844
1845 for ( i = 0; i < 100; i++ )
1846 {
1847 if ( pAdapterInfo )
1848 {
1849 free( pAdapterInfo );
1850 pAdapterInfo = NULL;
1851 }
1852
1853 pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
1854 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
1855
1856 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
1857
1858 if ( err != ERROR_BUFFER_OVERFLOW )
1859 {
1860 break;
1861 }
1862 }
1863
1864 // Windows doesn't really have a concept of a primary adapter,
1865 // so we're just going to iterate through all the adapters and
1866 // pick the first one that has an IP address assigned and
1867 // a gateway assigned
1868
1869 for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
1870 {
1871 if ( pAdapter->IpAddressList.IpAddress.String &&
1872 pAdapter->IpAddressList.IpAddress.String[0] &&
1873 pAdapter->GatewayList.IpAddress.String &&
1874 pAdapter->GatewayList.IpAddress.String[0] &&
1875 ( StringToAddress( primary, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
1876 ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) )
1877 {
1878 // Found one that will work
1879
1880 found = TRUE;
1881 break;
1882 }
1883 }
1884
1885 if ( !found )
1886 {
1887 // If we couldn't find one, then let's try the first one in the list
1888
1889 err = StringToAddress( primary, pAdapter->IpAddressList.IpAddress.String );
1890 require_noerr( err, exit );
1891
1892 found = TRUE;
1893 }
1894
1895 exit:
1896
1897 if ( pAdapterInfo )
1898 {
1899 free( pAdapterInfo );
1900 }
1901
1902 return err;
1903 }
1904
1905
1906 //===========================================================================================================================
1907 // dDNSPlatformDefaultBrowseDomainChanged
1908 //===========================================================================================================================
1909
1910 void
1911 dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add )
1912 {
1913 DEBUG_UNUSED( d );
1914 DEBUG_UNUSED( add );
1915
1916 // This is a no-op on Windows
1917 }
1918
1919
1920 //===========================================================================================================================
1921 // dDNSPlatformDefaultRegDomainChanged
1922 //===========================================================================================================================
1923
1924 void
1925 dDNSPlatformDefaultRegDomainChanged( const domainname * d, mDNSBool add )
1926 {
1927 DEBUG_UNUSED( d );
1928 DEBUG_UNUSED( add );
1929
1930 // This is a no-op on Windows
1931 }
1932
1933
1934 #if 0
1935 #pragma mark -
1936 #endif
1937
1938 //===========================================================================================================================
1939 // debugf_
1940 //===========================================================================================================================
1941
1942 #if( MDNS_DEBUGMSGS )
1943 void debugf_( const char *inFormat, ... )
1944 {
1945 char buffer[ 512 ];
1946 va_list args;
1947 mDNSu32 length;
1948
1949 va_start( args, inFormat );
1950 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
1951 va_end( args );
1952
1953 dlog( kDebugLevelInfo, "%s\n", buffer );
1954 }
1955 #endif
1956
1957 //===========================================================================================================================
1958 // verbosedebugf_
1959 //===========================================================================================================================
1960
1961 #if( MDNS_DEBUGMSGS > 1 )
1962 void verbosedebugf_( const char *inFormat, ... )
1963 {
1964 char buffer[ 512 ];
1965 va_list args;
1966 mDNSu32 length;
1967
1968 va_start( args, inFormat );
1969 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
1970 va_end( args );
1971
1972 dlog( kDebugLevelVerbose, "%s\n", buffer );
1973 }
1974 #endif
1975
1976 //===========================================================================================================================
1977 // LogMsg
1978 //===========================================================================================================================
1979
1980 /*
1981 void LogMsg( const char *inFormat, ... )
1982 {
1983 char buffer[ 512 ];
1984 va_list args;
1985 mDNSu32 length;
1986
1987 va_start( args, inFormat );
1988 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
1989 va_end( args );
1990
1991 dlog( kDebugLevelWarning, "%s\n", buffer );
1992 }
1993 */
1994
1995 #if 0
1996 #pragma mark -
1997 #pragma mark == Platform Internals ==
1998 #endif
1999
2000 //===========================================================================================================================
2001 // SetupSynchronizationObjects
2002 //===========================================================================================================================
2003
2004 mDNSlocal mStatus SetupSynchronizationObjects( mDNS * const inMDNS )
2005 {
2006 mStatus err;
2007
2008 InitializeCriticalSection( &inMDNS->p->lock );
2009 inMDNS->p->lockInitialized = mDNStrue;
2010
2011 inMDNS->p->cancelEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2012 err = translate_errno( inMDNS->p->cancelEvent, (mStatus) GetLastError(), kUnknownErr );
2013 require_noerr( err, exit );
2014
2015 inMDNS->p->quitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2016 err = translate_errno( inMDNS->p->quitEvent, (mStatus) GetLastError(), kUnknownErr );
2017 require_noerr( err, exit );
2018
2019 inMDNS->p->interfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2020 err = translate_errno( inMDNS->p->interfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
2021 require_noerr( err, exit );
2022
2023 inMDNS->p->wakeupEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2024 err = translate_errno( inMDNS->p->wakeupEvent, (mStatus) GetLastError(), kUnknownErr );
2025 require_noerr( err, exit );
2026
2027 exit:
2028 if( err )
2029 {
2030 TearDownSynchronizationObjects( inMDNS );
2031 }
2032 return( err );
2033 }
2034
2035 //===========================================================================================================================
2036 // TearDownSynchronizationObjects
2037 //===========================================================================================================================
2038
2039 mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS )
2040 {
2041 if( inMDNS->p->quitEvent )
2042 {
2043 CloseHandle( inMDNS->p->quitEvent );
2044 inMDNS->p->quitEvent = 0;
2045 }
2046 if( inMDNS->p->cancelEvent )
2047 {
2048 CloseHandle( inMDNS->p->cancelEvent );
2049 inMDNS->p->cancelEvent = 0;
2050 }
2051 if( inMDNS->p->interfaceListChangedEvent )
2052 {
2053 CloseHandle( inMDNS->p->interfaceListChangedEvent );
2054 inMDNS->p->interfaceListChangedEvent = 0;
2055 }
2056 if( inMDNS->p->wakeupEvent )
2057 {
2058 CloseHandle( inMDNS->p->wakeupEvent );
2059 inMDNS->p->wakeupEvent = 0;
2060 }
2061 if( inMDNS->p->lockInitialized )
2062 {
2063 DeleteCriticalSection( &inMDNS->p->lock );
2064 inMDNS->p->lockInitialized = mDNSfalse;
2065 }
2066 return( mStatus_NoError );
2067 }
2068
2069
2070 //===========================================================================================================================
2071 // SetupNiceName
2072 //===========================================================================================================================
2073
2074 mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS )
2075 {
2076 mStatus err = 0;
2077 char tempString[ 256 ];
2078 char utf8[ 256 ];
2079
2080 check( inMDNS );
2081
2082 // Set up the nice name.
2083 tempString[ 0 ] = '\0';
2084 utf8[0] = '\0';
2085
2086 // First try and open the registry key that contains the computer description value
2087 if (inMDNS->p->descKey == NULL)
2088 {
2089 LPCTSTR s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2090 err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &inMDNS->p->descKey);
2091 check_translated_errno( err == 0, errno_compat(), kNameErr );
2092
2093 if (err)
2094 {
2095 inMDNS->p->descKey = NULL;
2096 }
2097 }
2098
2099 // if we opened it...
2100 if (inMDNS->p->descKey != NULL)
2101 {
2102 TCHAR desc[256];
2103 DWORD descSize = sizeof( desc );
2104
2105 // look for the computer description
2106 err = RegQueryValueEx(inMDNS->p->descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
2107
2108 if ( !err )
2109 {
2110 err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
2111 }
2112
2113 if ( err )
2114 {
2115 utf8[ 0 ] = '\0';
2116 }
2117 }
2118
2119 // if we can't find it in the registry, then use the hostname of the machine
2120 if ( err || ( utf8[ 0 ] == '\0' ) )
2121 {
2122 err = gethostname( tempString, sizeof( tempString ) - 1 );
2123 check_translated_errno( err == 0, errno_compat(), kNameErr );
2124
2125 if( !err )
2126 {
2127 err = WindowsLatin1toUTF8( tempString, utf8, sizeof( utf8 ) );
2128 }
2129
2130 if ( err )
2131 {
2132 utf8[ 0 ] = '\0';
2133 }
2134 }
2135
2136 // if we can't get the hostname
2137 if ( err || ( utf8[ 0 ] == '\0' ) )
2138 {
2139 // Invalidate name so fall back to a default name.
2140
2141 strcpy( utf8, kMDNSDefaultName );
2142 }
2143
2144 utf8[ sizeof( utf8 ) - 1 ] = '\0';
2145 inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
2146 memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
2147
2148 dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
2149
2150 return( err );
2151 }
2152
2153
2154 //===========================================================================================================================
2155 // SetupHostName
2156 //===========================================================================================================================
2157
2158 mDNSlocal mStatus SetupHostName( mDNS * const inMDNS )
2159 {
2160 mStatus err = 0;
2161 char tempString[ 256 ];
2162 domainlabel tempLabel;
2163
2164 check( inMDNS );
2165
2166 // Set up the nice name.
2167 tempString[ 0 ] = '\0';
2168
2169 // use the hostname of the machine
2170 err = gethostname( tempString, sizeof( tempString ) - 1 );
2171 check_translated_errno( err == 0, errno_compat(), kNameErr );
2172
2173 // if we can't get the hostname
2174 if( err || ( tempString[ 0 ] == '\0' ) )
2175 {
2176 // Invalidate name so fall back to a default name.
2177
2178 strcpy( tempString, kMDNSDefaultName );
2179 }
2180
2181 tempString[ sizeof( tempString ) - 1 ] = '\0';
2182 tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
2183 memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
2184
2185 // Set up the host name.
2186
2187 ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
2188 if( inMDNS->hostlabel.c[ 0 ] == 0 )
2189 {
2190 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2191
2192 MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
2193 }
2194
2195 check( inMDNS->hostlabel.c[ 0 ] != 0 );
2196
2197 mDNS_SetFQDN( inMDNS );
2198
2199 dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
2200
2201 return( err );
2202 }
2203
2204 //===========================================================================================================================
2205 // SetupName
2206 //===========================================================================================================================
2207
2208 mDNSlocal mStatus SetupName( mDNS * const inMDNS )
2209 {
2210 mStatus err = 0;
2211
2212 check( inMDNS );
2213
2214 err = SetupNiceName( inMDNS );
2215 check_noerr( err );
2216
2217 err = SetupHostName( inMDNS );
2218 check_noerr( err );
2219
2220 return err;
2221 }
2222
2223
2224 //===========================================================================================================================
2225 // SetupInterfaceList
2226 //===========================================================================================================================
2227
2228 mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
2229 {
2230 mStatus err;
2231 mDNSInterfaceData ** next;
2232 mDNSInterfaceData * ifd;
2233 struct ifaddrs * addrs;
2234 struct ifaddrs * p;
2235 struct ifaddrs * loopback;
2236 u_int flagMask;
2237 u_int flagTest;
2238 BOOL foundUnicastSock4DestAddr;
2239 BOOL foundUnicastSock6DestAddr;
2240
2241 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
2242 check( inMDNS );
2243 check( inMDNS->p );
2244
2245 addrs = NULL;
2246 foundUnicastSock4DestAddr = FALSE;
2247 foundUnicastSock6DestAddr = FALSE;
2248
2249 // Tear down any existing interfaces that may be set up.
2250
2251 TearDownInterfaceList( inMDNS );
2252
2253 // Set up the name of this machine.
2254
2255 err = SetupName( inMDNS );
2256 check_noerr( err );
2257
2258 // Set up the interface list change notification.
2259
2260 err = SetupNotifications( inMDNS );
2261 check_noerr( err );
2262
2263 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2264 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2265
2266 err = getifaddrs( &addrs );
2267 require_noerr( err, exit );
2268
2269 loopback = NULL;
2270 next = &inMDNS->p->interfaceList;
2271
2272 flagMask = IFF_UP | IFF_MULTICAST | IFF_POINTTOPOINT;
2273 flagTest = IFF_UP | IFF_MULTICAST;
2274
2275 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2276 for( p = addrs; p; p = p->ifa_next )
2277 {
2278 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2279 {
2280 continue;
2281 }
2282 if( p->ifa_flags & IFF_LOOPBACK )
2283 {
2284 if( !loopback )
2285 {
2286 loopback = p;
2287 }
2288 continue;
2289 }
2290 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2291 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
2292
2293 err = SetupInterface( inMDNS, p, &ifd );
2294 require_noerr( err, exit );
2295
2296 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2297 // of determing the destination address of a packet that is sent to us.
2298 // For multicast packets, that's easy to determine. But for the unicast
2299 // sockets, we'll fake it by taking the address of the first interface
2300 // that is successfully setup.
2301
2302 if ( !foundUnicastSock4DestAddr )
2303 {
2304 inMDNS->p->unicastSock4DestAddr = ifd->interfaceInfo.ip;
2305 foundUnicastSock4DestAddr = TRUE;
2306 }
2307
2308 *next = ifd;
2309 next = &ifd->next;
2310 ++inMDNS->p->interfaceCount;
2311
2312
2313 }
2314 #endif
2315
2316 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2317
2318 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2319 for( p = addrs; p; p = p->ifa_next )
2320 {
2321 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2322 {
2323 continue;
2324 }
2325 if( p->ifa_flags & IFF_LOOPBACK )
2326 {
2327 if( !loopback )
2328 {
2329 loopback = p;
2330 }
2331 continue;
2332 }
2333 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2334 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
2335
2336 err = SetupInterface( inMDNS, p, &ifd );
2337 require_noerr( err, exit );
2338
2339 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2340 // of determing the destination address of a packet that is sent to us.
2341 // For multicast packets, that's easy to determine. But for the unicast
2342 // sockets, we'll fake it by taking the address of the first interface
2343 // that is successfully setup.
2344
2345 if ( !foundUnicastSock6DestAddr )
2346 {
2347 inMDNS->p->unicastSock6DestAddr = ifd->interfaceInfo.ip;
2348 foundUnicastSock6DestAddr = TRUE;
2349 }
2350
2351 *next = ifd;
2352 next = &ifd->next;
2353 ++inMDNS->p->interfaceCount;
2354 }
2355 #endif
2356
2357 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2358
2359 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2360
2361 flagMask |= IFF_LOOPBACK;
2362 flagTest |= IFF_LOOPBACK;
2363
2364 for( p = addrs; p; p = p->ifa_next )
2365 {
2366 if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2367 {
2368 continue;
2369 }
2370 if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
2371 {
2372 continue;
2373 }
2374 loopback = p;
2375 break;
2376 }
2377
2378 #endif
2379
2380 if( !inMDNS->p->interfaceList && loopback )
2381 {
2382 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2383 loopback->ifa_name ? loopback->ifa_name : "<null>", loopback->ifa_extra.index, loopback->ifa_addr );
2384
2385 err = SetupInterface( inMDNS, loopback, &ifd );
2386 require_noerr( err, exit );
2387
2388 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2389
2390 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2391 // of determing the destination address of a packet that is sent to us.
2392 // For multicast packets, that's easy to determine. But for the unicast
2393 // sockets, we'll fake it by taking the address of the first interface
2394 // that is successfully setup.
2395
2396 if ( !foundUnicastSock4DestAddr )
2397 {
2398 inMDNS->p->unicastSock4DestAddr = ifd->defaultAddr;
2399 foundUnicastSock4DestAddr = TRUE;
2400 }
2401 #endif
2402
2403 *next = ifd;
2404 next = &ifd->next;
2405 ++inMDNS->p->interfaceCount;
2406 }
2407
2408 exit:
2409 if( err )
2410 {
2411 TearDownInterfaceList( inMDNS );
2412 }
2413 if( addrs )
2414 {
2415 freeifaddrs( addrs );
2416 }
2417 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
2418 return( err );
2419 }
2420
2421 //===========================================================================================================================
2422 // TearDownInterfaceList
2423 //===========================================================================================================================
2424
2425 mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS )
2426 {
2427 mStatus err;
2428 mDNSInterfaceData ** p;
2429 mDNSInterfaceData * ifd;
2430
2431 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
2432 check( inMDNS );
2433 check( inMDNS->p );
2434
2435 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2436 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2437 // so that remove events that occur after an interface goes away can still report the correct interface.
2438
2439 p = &inMDNS->p->inactiveInterfaceList;
2440 while( *p )
2441 {
2442 ifd = *p;
2443 if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
2444 {
2445 p = &ifd->next;
2446 continue;
2447 }
2448
2449 dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
2450 *p = ifd->next;
2451 free( ifd );
2452 }
2453
2454 // Tear down interface list change notifications.
2455
2456 err = TearDownNotifications( inMDNS );
2457 check_noerr( err );
2458
2459 // Tear down all the interfaces.
2460
2461 while( inMDNS->p->interfaceList )
2462 {
2463 ifd = inMDNS->p->interfaceList;
2464 inMDNS->p->interfaceList = ifd->next;
2465
2466 TearDownInterface( inMDNS, ifd );
2467 }
2468 inMDNS->p->interfaceCount = 0;
2469
2470 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
2471 return( mStatus_NoError );
2472 }
2473
2474 //===========================================================================================================================
2475 // SetupInterface
2476 //===========================================================================================================================
2477
2478 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
2479 {
2480 mDNSInterfaceData * ifd;
2481 mDNSInterfaceData * p;
2482 SocketRef sock;
2483 mStatus err;
2484
2485 ifd = NULL;
2486 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
2487 check( inMDNS );
2488 check( inMDNS->p );
2489 check( inIFA );
2490 check( inIFA->ifa_addr );
2491 check( outIFD );
2492
2493 // Allocate memory for the interface and initialize it.
2494
2495 ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
2496 require_action( ifd, exit, err = mStatus_NoMemoryErr );
2497 ifd->sock = kInvalidSocketRef;
2498 ifd->index = inIFA->ifa_extra.index;
2499 ifd->scopeID = inIFA->ifa_extra.index;
2500
2501 check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
2502 strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
2503 ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
2504
2505 strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
2506 ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
2507
2508 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2509 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2510 // on a large configured network, which means there's a good chance that most or all the other devices on that
2511 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2512 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2513 // devices on a large configured network, so we are willing to make that sacrifice.
2514
2515 ifd->interfaceInfo.McastTxRx = mDNStrue;
2516 ifd->interfaceInfo.InterfaceID = NULL;
2517
2518 for( p = inMDNS->p->interfaceList; p; p = p->next )
2519 {
2520 if ( strcmp( p->name, ifd->name ) == 0 )
2521 {
2522 if (!ifd->interfaceInfo.InterfaceID)
2523 {
2524 p->scopeID = ifd->scopeID;
2525 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) p;
2526 }
2527
2528 if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
2529 ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
2530 ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
2531 {
2532 ifd->interfaceInfo.McastTxRx = mDNSfalse;
2533 }
2534
2535 break;
2536 }
2537 }
2538
2539 if ( !ifd->interfaceInfo.InterfaceID )
2540 {
2541 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
2542 }
2543
2544 // Set up a socket for this interface (if needed).
2545
2546 if( ifd->interfaceInfo.McastTxRx )
2547 {
2548 err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &sock );
2549 require_noerr( err, exit );
2550 ifd->sock = sock;
2551 ifd->defaultAddr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
2552
2553 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2554
2555 #if( !TARGET_OS_WINDOWS_CE )
2556 {
2557 DWORD size;
2558
2559 err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
2560 &ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL );
2561 if( err != 0 )
2562 {
2563 ifd->wsaRecvMsgFunctionPtr = NULL;
2564 }
2565 }
2566 #endif
2567
2568 // Set up the read pending event and associate it so we can block until data is available for this socket.
2569
2570 ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2571 err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
2572 require_noerr( err, exit );
2573
2574 err = WSAEventSelect( ifd->sock, ifd->readPendingEvent, FD_READ );
2575 require_noerr( err, exit );
2576 }
2577 else
2578 {
2579 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
2580
2581 ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2582 err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
2583 require_noerr( err, exit );
2584 }
2585
2586 // Register this interface with mDNS.
2587
2588 err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
2589 require_noerr( err, exit );
2590
2591 err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
2592 require_noerr( err, exit );
2593
2594 ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
2595
2596 err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, 0 );
2597 require_noerr( err, exit );
2598 ifd->hostRegistered = mDNStrue;
2599
2600 dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
2601
2602 // Success!
2603
2604 *outIFD = ifd;
2605 ifd = NULL;
2606
2607 exit:
2608 if( ifd )
2609 {
2610 TearDownInterface( inMDNS, ifd );
2611 }
2612 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
2613 return( err );
2614 }
2615
2616 //===========================================================================================================================
2617 // TearDownInterface
2618 //===========================================================================================================================
2619
2620 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
2621 {
2622 SocketRef sock;
2623
2624 check( inMDNS );
2625 check( inIFD );
2626
2627 // Deregister this interface with mDNS.
2628
2629 dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
2630
2631 if( inIFD->hostRegistered )
2632 {
2633 inIFD->hostRegistered = mDNSfalse;
2634 mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo );
2635 }
2636
2637 // Tear down the multicast socket.
2638
2639 if( inIFD->readPendingEvent )
2640 {
2641 CloseHandle( inIFD->readPendingEvent );
2642 inIFD->readPendingEvent = 0;
2643 }
2644
2645 sock = inIFD->sock;
2646 inIFD->sock = kInvalidSocketRef;
2647 if( IsValidSocket( sock ) )
2648 {
2649 close_compat( sock );
2650 }
2651
2652 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2653 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2654
2655 if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
2656 {
2657 inIFD->next = inMDNS->p->inactiveInterfaceList;
2658 inMDNS->p->inactiveInterfaceList = inIFD;
2659 dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
2660 }
2661 else
2662 {
2663 dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
2664 free( inIFD );
2665 }
2666 return( mStatus_NoError );
2667 }
2668
2669 //===========================================================================================================================
2670 // SetupSocket
2671 //===========================================================================================================================
2672
2673 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef )
2674 {
2675 mStatus err;
2676 SocketRef sock;
2677 int option;
2678
2679 DEBUG_UNUSED( inMDNS );
2680
2681 dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
2682 check( inMDNS );
2683 check( outSocketRef );
2684
2685 // Set up an IPv4 or IPv6 UDP socket.
2686
2687 sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
2688 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2689 require_noerr( err, exit );
2690
2691 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2692 // if we're creating a multicast socket
2693
2694 if ( port.NotAnInteger )
2695 {
2696 option = 1;
2697 err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
2698 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2699 }
2700
2701 if( inAddr->sa_family == AF_INET )
2702 {
2703 mDNSv4Addr ipv4;
2704 struct sockaddr_in sa4;
2705 struct ip_mreq mreqv4;
2706
2707 // Bind the socket to the desired port
2708
2709 ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
2710 memset( &sa4, 0, sizeof( sa4 ) );
2711 sa4.sin_family = AF_INET;
2712 sa4.sin_port = port.NotAnInteger;
2713 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
2714
2715 err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
2716 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
2717
2718 // Turn on option to receive destination addresses and receiving interface.
2719
2720 option = 1;
2721 err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
2722 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2723
2724 if (port.NotAnInteger)
2725 {
2726 // Join the all-DNS multicast group so we receive Multicast DNS packets
2727
2728 mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
2729 mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
2730 err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
2731 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2732
2733 // Specify the interface to send multicast packets on this socket.
2734
2735 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
2736 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
2737 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2738
2739 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2740
2741 option = 1;
2742 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
2743 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2744 }
2745
2746 // Send unicast packets with TTL 255 (helps against spoofing).
2747
2748 option = 255;
2749 err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
2750 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2751
2752 // Send multicast packets with TTL 255 (helps against spoofing).
2753
2754 option = 255;
2755 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
2756 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2757
2758 }
2759 else if( inAddr->sa_family == AF_INET6 )
2760 {
2761 struct sockaddr_in6 * sa6p;
2762 struct sockaddr_in6 sa6;
2763 struct ipv6_mreq mreqv6;
2764
2765 sa6p = (struct sockaddr_in6 *) inAddr;
2766
2767 // Bind the socket to the desired port
2768
2769 memset( &sa6, 0, sizeof( sa6 ) );
2770 sa6.sin6_family = AF_INET6;
2771 sa6.sin6_port = port.NotAnInteger;
2772 sa6.sin6_flowinfo = 0;
2773 sa6.sin6_addr = sa6p->sin6_addr;
2774 sa6.sin6_scope_id = sa6p->sin6_scope_id;
2775
2776 err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
2777 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
2778
2779 // Turn on option to receive destination addresses and receiving interface.
2780
2781 option = 1;
2782 err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
2783 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2784
2785 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
2786 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
2787 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
2788
2789 #if( defined( IPV6_V6ONLY ) )
2790 option = 1;
2791 err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
2792 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2793 #endif
2794
2795 if ( port.NotAnInteger )
2796 {
2797 // Join the all-DNS multicast group so we receive Multicast DNS packets.
2798
2799 mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
2800 mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
2801 err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
2802 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2803
2804 // Specify the interface to send multicast packets on this socket.
2805
2806 option = (int) sa6p->sin6_scope_id;
2807 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
2808 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2809
2810 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
2811
2812 option = 1;
2813 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
2814 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2815 }
2816
2817 // Send unicast packets with TTL 255 (helps against spoofing).
2818
2819 option = 255;
2820 err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
2821 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2822
2823 // Send multicast packets with TTL 255 (helps against spoofing).
2824
2825 option = 255;
2826 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
2827 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2828 }
2829 else
2830 {
2831 dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
2832 err = kUnsupportedErr;
2833 goto exit;
2834 }
2835
2836 // Success!
2837
2838 *outSocketRef = sock;
2839 sock = kInvalidSocketRef;
2840 err = mStatus_NoError;
2841
2842 exit:
2843 if( IsValidSocket( sock ) )
2844 {
2845 close_compat( sock );
2846 }
2847 return( err );
2848 }
2849
2850 //===========================================================================================================================
2851 // SetupSocket
2852 //===========================================================================================================================
2853
2854 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
2855 {
2856 mStatus err;
2857
2858 check( inSA );
2859 check( outIP );
2860
2861 if( inSA->sa_family == AF_INET )
2862 {
2863 struct sockaddr_in * sa4;
2864
2865 sa4 = (struct sockaddr_in *) inSA;
2866 outIP->type = mDNSAddrType_IPv4;
2867 outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
2868 if( outPort )
2869 {
2870 outPort->NotAnInteger = sa4->sin_port;
2871 }
2872 err = mStatus_NoError;
2873 }
2874 else if( inSA->sa_family == AF_INET6 )
2875 {
2876 struct sockaddr_in6 * sa6;
2877
2878 sa6 = (struct sockaddr_in6 *) inSA;
2879 outIP->type = mDNSAddrType_IPv6;
2880 outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
2881 if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
2882 {
2883 outIP->ip.v6.w[ 1 ] = 0;
2884 }
2885 if( outPort )
2886 {
2887 outPort->NotAnInteger = sa6->sin6_port;
2888 }
2889 err = mStatus_NoError;
2890 }
2891 else
2892 {
2893 dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
2894 err = mStatus_BadParamErr;
2895 }
2896 return( err );
2897 }
2898
2899 //===========================================================================================================================
2900 // SetupNotifications
2901 //===========================================================================================================================
2902
2903 mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS )
2904 {
2905 mStatus err;
2906 SocketRef sock;
2907 unsigned long param;
2908 int inBuffer;
2909 int outBuffer;
2910 DWORD outSize;
2911
2912 // Register to listen for address list changes.
2913
2914 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
2915 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2916 require_noerr( err, exit );
2917 inMDNS->p->interfaceListChangedSocket = sock;
2918
2919 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
2920 // when a change to the interface list is detected.
2921
2922 param = 1;
2923 err = ioctlsocket( sock, FIONBIO, &param );
2924 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
2925 require_noerr( err, exit );
2926
2927 inBuffer = 0;
2928 outBuffer = 0;
2929 err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
2930 if( err < 0 )
2931 {
2932 check( errno_compat() == WSAEWOULDBLOCK );
2933 }
2934
2935 err = WSAEventSelect( sock, inMDNS->p->interfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
2936 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
2937 require_noerr( err, exit );
2938
2939 inMDNS->p->descChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
2940 err = translate_errno( inMDNS->p->descChangedEvent, (mStatus) GetLastError(), kUnknownErr );
2941 require_noerr( err, exit );
2942
2943 if (inMDNS->p->descKey != NULL)
2944 {
2945 err = RegNotifyChangeKeyValue(inMDNS->p->descKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->descChangedEvent, TRUE);
2946 require_noerr( err, exit );
2947 }
2948
2949 // This will catch all changes to tcp/ip networking, including changes to the domain search list
2950
2951 inMDNS->p->tcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
2952 err = translate_errno( inMDNS->p->tcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
2953 require_noerr( err, exit );
2954
2955 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS->p->tcpipKey );
2956 require_noerr( err, exit );
2957
2958 err = RegNotifyChangeKeyValue(inMDNS->p->tcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->tcpipChangedEvent, TRUE);
2959 require_noerr( err, exit );
2960
2961 // This will catch all changes to ddns configuration
2962
2963 inMDNS->p->ddnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
2964 err = translate_errno( inMDNS->p->ddnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
2965 require_noerr( err, exit );
2966
2967 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName TEXT("\\Parameters\\DynDNS\\Setup"), &inMDNS->p->ddnsKey );
2968 require_noerr( err, exit );
2969
2970 err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
2971 require_noerr( err, exit );
2972
2973 exit:
2974 if( err )
2975 {
2976 TearDownNotifications( inMDNS );
2977 }
2978 return( err );
2979 }
2980
2981 //===========================================================================================================================
2982 // TearDownNotifications
2983 //===========================================================================================================================
2984
2985 mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS )
2986 {
2987 if( IsValidSocket( inMDNS->p->interfaceListChangedSocket ) )
2988 {
2989 close_compat( inMDNS->p->interfaceListChangedSocket );
2990 inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
2991 }
2992
2993 if ( inMDNS->p->descChangedEvent != NULL )
2994 {
2995 CloseHandle( inMDNS->p->descChangedEvent );
2996 inMDNS->p->descChangedEvent = NULL;
2997 }
2998
2999 if ( inMDNS->p->descKey != NULL )
3000 {
3001 RegCloseKey( inMDNS->p->descKey );
3002 inMDNS->p->descKey = NULL;
3003 }
3004
3005 if ( inMDNS->p->tcpipChangedEvent != NULL )
3006 {
3007 CloseHandle( inMDNS->p->tcpipChangedEvent );
3008 inMDNS->p->tcpipChangedEvent = NULL;
3009 }
3010
3011 if ( inMDNS->p->ddnsChangedEvent != NULL )
3012 {
3013 CloseHandle( inMDNS->p->ddnsChangedEvent );
3014 inMDNS->p->ddnsChangedEvent = NULL;
3015 }
3016
3017 if ( inMDNS->p->ddnsKey != NULL )
3018 {
3019 RegCloseKey( inMDNS->p->ddnsKey );
3020 inMDNS->p->ddnsKey = NULL;
3021 }
3022
3023 return( mStatus_NoError );
3024 }
3025
3026 #if 0
3027 #pragma mark -
3028 #endif
3029
3030 //===========================================================================================================================
3031 // SetupThread
3032 //===========================================================================================================================
3033
3034 mDNSlocal mStatus SetupThread( mDNS * const inMDNS )
3035 {
3036 mStatus err;
3037 HANDLE threadHandle;
3038 unsigned threadID;
3039 DWORD result;
3040
3041 dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread\n" );
3042
3043 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
3044 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
3045
3046 inMDNS->p->initEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
3047 err = translate_errno( inMDNS->p->initEvent, (mStatus) GetLastError(), kUnknownErr );
3048 require_noerr( err, exit );
3049
3050 inMDNS->p->initStatus = mStatus_Invalid;
3051
3052 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
3053 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3054
3055 threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, ProcessingThread, inMDNS, 0, &threadID );
3056 err = translate_errno( threadHandle, (mStatus) GetLastError(), kUnknownErr );
3057 require_noerr( err, exit );
3058
3059 result = WaitForSingleObject( inMDNS->p->initEvent, INFINITE );
3060 err = translate_errno( result == WAIT_OBJECT_0, (mStatus) GetLastError(), kUnknownErr );
3061 require_noerr( err, exit );
3062 err = inMDNS->p->initStatus;
3063 require_noerr( err, exit );
3064
3065 exit:
3066 if( inMDNS->p->initEvent )
3067 {
3068 CloseHandle( inMDNS->p->initEvent );
3069 inMDNS->p->initEvent = 0;
3070 }
3071 dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread done (err=%d %m)\n", err, err );
3072 return( err );
3073 }
3074
3075 //===========================================================================================================================
3076 // TearDownThread
3077 //===========================================================================================================================
3078
3079 mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS )
3080 {
3081 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
3082 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
3083
3084 if( inMDNS->p->cancelEvent )
3085 {
3086 BOOL wasSet;
3087 DWORD result;
3088
3089 wasSet = SetEvent( inMDNS->p->cancelEvent );
3090 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
3091
3092 if( inMDNS->p->quitEvent )
3093 {
3094 result = WaitForSingleObject( inMDNS->p->quitEvent, 5 * 1000 );
3095 check_translated_errno( result == WAIT_OBJECT_0, GetLastError(), kUnknownErr );
3096 }
3097 }
3098 return( mStatus_NoError );
3099 }
3100
3101 //===========================================================================================================================
3102 // ProcessingThread
3103 //===========================================================================================================================
3104
3105 mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
3106 {
3107 mDNS * m;
3108 int done;
3109 mStatus err;
3110 HANDLE * waitList;
3111 int waitListCount;
3112 DWORD result;
3113 BOOL wasSet;
3114
3115 check( inParam );
3116
3117 m = (mDNS *) inParam;
3118 err = ProcessingThreadInitialize( m );
3119 require_noerr( err, exit );
3120
3121 done = 0;
3122 while( !done )
3123 {
3124 // Set up the list of objects we'll be waiting on.
3125
3126 waitList = NULL;
3127 waitListCount = 0;
3128 err = ProcessingThreadSetupWaitList( m, &waitList, &waitListCount );
3129 require_noerr( err, exit );
3130
3131 // Main processing loop.
3132
3133 gWaitListChanged = FALSE;
3134
3135 for( ;; )
3136 {
3137 // Give the mDNS core a chance to do its work and determine next event time.
3138
3139 mDNSs32 interval = mDNS_Execute(m) - mDNS_TimeNow(m);
3140
3141 if ( gWaitListChanged )
3142 {
3143 break;
3144 }
3145
3146 if (m->p->idleThreadCallback)
3147 {
3148 interval = m->p->idleThreadCallback(m, interval);
3149 }
3150 if (interval < 0) interval = 0;
3151 else if (interval > (0x7FFFFFFF / 1000)) interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
3152 else interval = (interval * 1000) / mDNSPlatformOneSecond;
3153
3154 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
3155
3156 result = WaitForMultipleObjects( (DWORD) waitListCount, waitList, FALSE, (DWORD) interval );
3157 if( result == WAIT_TIMEOUT )
3158 {
3159 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
3160
3161 dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
3162 continue;
3163 }
3164 else if( result == kWaitListCancelEvent )
3165 {
3166 // Cancel event. Set the done flag and break to exit.
3167
3168 dlog( kDebugLevelVerbose, DEBUG_NAME "canceling...\n" );
3169 done = 1;
3170 break;
3171 }
3172 else if( result == kWaitListInterfaceListChangedEvent )
3173 {
3174 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
3175
3176 ProcessingThreadInterfaceListChanged( m );
3177 break;
3178 }
3179 else if( result == kWaitListWakeupEvent )
3180 {
3181 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
3182
3183 dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup for mDNS_Execute\n" );
3184 continue;
3185 }
3186 else if ( result == kWaitListComputerDescriptionEvent )
3187 {
3188 //
3189 // The computer description might have changed
3190 //
3191 ProcessingThreadComputerDescriptionChanged( m );
3192 break;
3193 }
3194 else if ( result == kWaitListTCPIPEvent )
3195 {
3196 //
3197 // The TCP/IP might have changed
3198 //
3199 ProcessingThreadTCPIPConfigChanged( m );
3200 break;
3201 }
3202 else if ( result == kWaitListDynDNSEvent )
3203 {
3204 //
3205 // The DynDNS config might have changed
3206 //
3207 ProcessingThreadDynDNSConfigChanged( m );
3208 break;
3209 }
3210 else
3211 {
3212 int waitItemIndex;
3213
3214 // Socket data available event. Determine which socket and process the packet.
3215
3216 waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
3217 dlog( kDebugLevelChatty, DEBUG_NAME "socket data available on socket index %d\n", waitItemIndex );
3218 check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
3219 if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
3220 {
3221 HANDLE signaledObject;
3222 int n = 0;
3223 mDNSInterfaceData * ifd;
3224 mDNSTCPConnectionData * tcd;
3225
3226 signaledObject = waitList[ waitItemIndex ];
3227
3228 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3229 if ( m->p->unicastSock4ReadEvent == signaledObject )
3230 {
3231 ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock4 );
3232 ++n;
3233 }
3234 #endif
3235
3236 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3237 if ( m->p->unicastSock6ReadEvent == signaledObject )
3238 {
3239 ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock6 );
3240 ++n;
3241 }
3242 #endif
3243
3244 for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
3245 {
3246 if( ifd->readPendingEvent == signaledObject )
3247 {
3248 ProcessingThreadProcessPacket( m, ifd, ifd->sock );
3249 ++n;
3250 }
3251 }
3252
3253 for ( tcd = gTCPConnectionList; tcd; tcd = tcd->next )
3254 {
3255 if ( tcd->pendingEvent == signaledObject )
3256 {
3257 mDNSBool connect = FALSE;
3258
3259 if ( !tcd->connected )
3260 {
3261 tcd->connected = mDNStrue;
3262 connect = mDNStrue;
3263 }
3264
3265 tcd->callback( ( int ) tcd->sock, tcd->context, connect );
3266
3267 ++n;
3268
3269 break;
3270 }
3271 }
3272
3273 check( n > 0 );
3274 }
3275 else
3276 {
3277 // Unexpected wait result.
3278
3279 dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
3280 }
3281 }
3282 }
3283
3284 // Release the wait list.
3285
3286 if( waitList )
3287 {
3288 free( waitList );
3289 waitList = NULL;
3290 waitListCount = 0;
3291 }
3292 }
3293
3294 // Signal the quit event to indicate that the thread is finished.
3295
3296 exit:
3297 wasSet = SetEvent( m->p->quitEvent );
3298 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
3299
3300 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
3301 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
3302
3303 _endthreadex_compat( 0 );
3304 return( 0 );
3305 }
3306
3307 //===========================================================================================================================
3308 // ProcessingThreadInitialize
3309 //===========================================================================================================================
3310
3311 mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
3312 {
3313 mStatus err;
3314 BOOL wasSet;
3315
3316 inMDNS->p->threadID = GetCurrentThreadId();
3317
3318 err = SetupInterfaceList( inMDNS );
3319 require_noerr( err, exit );
3320
3321 err = dDNS_Setup( inMDNS );
3322 require_noerr( err, exit );
3323
3324 err = dDNS_InitDNSConfig( inMDNS );
3325 require_noerr( err, exit );
3326
3327 exit:
3328
3329 if( err )
3330 {
3331 TearDownInterfaceList( inMDNS );
3332 }
3333 inMDNS->p->initStatus = err;
3334
3335 wasSet = SetEvent( inMDNS->p->initEvent );
3336 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
3337 return( err );
3338 }
3339
3340 //===========================================================================================================================
3341 // ProcessingThreadSetupWaitList
3342 //===========================================================================================================================
3343
3344 mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
3345 {
3346 mStatus err;
3347 int waitListCount;
3348 HANDLE * waitList;
3349 HANDLE * waitItemPtr;
3350 mDNSInterfaceData * ifd;
3351 mDNSTCPConnectionData * tcd;
3352
3353 dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
3354 check( inMDNS );
3355 check( inMDNS->p );
3356 check( outWaitList );
3357 check( outWaitListCount );
3358
3359 // Allocate an array to hold all the objects to wait on.
3360
3361 waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount + gTCPConnections;
3362 waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
3363 require_action( waitList, exit, err = mStatus_NoMemoryErr );
3364 waitItemPtr = waitList;
3365
3366 // Add the fixed wait items to the beginning of the list.
3367
3368 *waitItemPtr++ = inMDNS->p->cancelEvent;
3369 *waitItemPtr++ = inMDNS->p->interfaceListChangedEvent;
3370 *waitItemPtr++ = inMDNS->p->wakeupEvent;
3371 *waitItemPtr++ = inMDNS->p->descChangedEvent;
3372 *waitItemPtr++ = inMDNS->p->tcpipChangedEvent;
3373 *waitItemPtr++ = inMDNS->p->ddnsChangedEvent;
3374
3375 // Append all the dynamic wait items to the list.
3376 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
3377 *waitItemPtr++ = inMDNS->p->unicastSock4ReadEvent;
3378 #endif
3379
3380 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
3381 *waitItemPtr++ = inMDNS->p->unicastSock6ReadEvent;
3382 #endif
3383
3384 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
3385 {
3386 *waitItemPtr++ = ifd->readPendingEvent;
3387 }
3388
3389 for ( tcd = gTCPConnectionList; tcd; tcd = tcd->next )
3390 {
3391 *waitItemPtr++ = tcd->pendingEvent;
3392 }
3393
3394 check( (int)( waitItemPtr - waitList ) == waitListCount );
3395
3396 *outWaitList = waitList;
3397 *outWaitListCount = waitListCount;
3398 waitList = NULL;
3399 err = mStatus_NoError;
3400
3401 exit:
3402 if( waitList )
3403 {
3404 free( waitList );
3405 }
3406 dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list done (err=%d %m)\n", err, err );
3407 return( err );
3408 }
3409
3410 //===========================================================================================================================
3411 // ProcessingThreadProcessPacket
3412 //===========================================================================================================================
3413
3414 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock )
3415 {
3416 OSStatus err;
3417 const mDNSInterfaceID iid = inIFD ? inIFD->interfaceInfo.InterfaceID : NULL;
3418 LPFN_WSARECVMSG recvMsgPtr;
3419 mDNSAddr srcAddr;
3420 mDNSIPPort srcPort;
3421 mDNSAddr dstAddr;
3422 mDNSIPPort dstPort;
3423 mDNSu8 ttl;
3424 struct sockaddr_storage addr;
3425 DNSMessage packet;
3426 mDNSu8 * end;
3427 int n;
3428
3429 check( inMDNS );
3430 check( IsValidSocket( inSock ) );
3431
3432 // Set up the default in case the packet info options are not supported or reported correctly.
3433
3434 if ( inIFD )
3435 {
3436 recvMsgPtr = inIFD->wsaRecvMsgFunctionPtr;
3437 dstAddr = inIFD->defaultAddr;
3438 dstPort = MulticastDNSPort;
3439 ttl = 255;
3440 }
3441 else if ( inSock == inMDNS->p->unicastSock4 )
3442 {
3443 recvMsgPtr = inMDNS->p->unicastSock4RecvMsgPtr;
3444 dstAddr = inMDNS->p->unicastSock4DestAddr;
3445 dstPort = zeroIPPort;
3446 ttl = 255;
3447 }
3448 else if ( inSock == inMDNS->p->unicastSock6 )
3449 {
3450 recvMsgPtr = inMDNS->p->unicastSock6RecvMsgPtr;
3451 dstAddr = inMDNS->p->unicastSock6DestAddr;
3452 dstPort = zeroIPPort;
3453 ttl = 255;
3454 }
3455 else
3456 {
3457 dlog( kDebugLevelError, DEBUG_NAME "packet received on unknown socket\n" );
3458 goto exit;
3459 }
3460
3461 #if( !TARGET_OS_WINDOWS_CE )
3462 if( recvMsgPtr )
3463 {
3464 WSAMSG msg;
3465 WSABUF buf;
3466 uint8_t controlBuffer[ 128 ];
3467 DWORD size;
3468 LPWSACMSGHDR header;
3469
3470 // Set up the buffer and read the packet.
3471
3472 msg.name = (LPSOCKADDR) &addr;
3473 msg.namelen = (INT) sizeof( addr );
3474 buf.buf = (char *) &packet;
3475 buf.len = (u_long) sizeof( packet );
3476 msg.lpBuffers = &buf;
3477 msg.dwBufferCount = 1;
3478 msg.Control.buf = (char *) controlBuffer;
3479 msg.Control.len = (u_long) sizeof( controlBuffer );
3480 msg.dwFlags = 0;
3481
3482 err = recvMsgPtr( inSock, &msg, &size, NULL, NULL );
3483 err = translate_errno( err == 0, (OSStatus) GetLastError(), kUnknownErr );
3484 require_noerr( err, exit );
3485 n = (int) size;
3486
3487 // Parse the control information. Reject packets received on the wrong interface.
3488
3489 for( header = WSA_CMSG_FIRSTHDR( &msg ); header; header = WSA_CMSG_NXTHDR( &msg, header ) )
3490 {
3491 if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
3492 {
3493 IN_PKTINFO * ipv4PacketInfo;
3494
3495 ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
3496
3497 if ( inIFD )
3498 {
3499 require_action( ipv4PacketInfo->ipi_ifindex == ( inIFD->index >> 8 ), exit, err = kMismatchErr );
3500 }
3501
3502 dstAddr.type = mDNSAddrType_IPv4;
3503 dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
3504 }
3505 else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
3506 {
3507 IN6_PKTINFO * ipv6PacketInfo;
3508
3509 ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
3510
3511 if ( inIFD )
3512 {
3513 require_action( ipv6PacketInfo->ipi6_ifindex == inIFD->index, exit, err = kMismatchErr );
3514 }
3515
3516 dstAddr.type = mDNSAddrType_IPv6;
3517 dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
3518 }
3519 }
3520 }
3521 else
3522 #endif
3523 {
3524 int addrSize;
3525
3526 addrSize = sizeof( addr );
3527 n = recvfrom( inSock, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
3528 err = translate_errno( n > 0, errno_compat(), kUnknownErr );
3529 require_noerr( err, exit );
3530 }
3531 SockAddrToMDNSAddr( (struct sockaddr *) &addr, &srcAddr, &srcPort );
3532
3533 // Dispatch the packet to mDNS.
3534
3535 dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
3536 dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", n );
3537 dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
3538 dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
3539
3540 if ( inIFD )
3541 {
3542 dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
3543 }
3544
3545 dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
3546
3547 end = ( (mDNSu8 *) &packet ) + n;
3548 mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
3549
3550 exit:
3551 return;
3552 }
3553
3554 //===========================================================================================================================
3555 // ProcessingThreadInterfaceListChanged
3556 //===========================================================================================================================
3557
3558 mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
3559 {
3560 mStatus err;
3561
3562 dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
3563 check( inMDNS );
3564
3565 if (inMDNS->p->interfaceListChangedCallback)
3566 {
3567 inMDNS->p->interfaceListChangedCallback(inMDNS);
3568 }
3569
3570 mDNSPlatformLock( inMDNS );
3571
3572 // Tear down the existing interfaces and set up new ones using the new IP info.
3573
3574 err = TearDownInterfaceList( inMDNS );
3575 check_noerr( err );
3576
3577 err = SetupInterfaceList( inMDNS );
3578 check_noerr( err );
3579
3580 mDNSPlatformUnlock( inMDNS );
3581
3582 // Inform clients of the change.
3583
3584 if( inMDNS->MainCallback )
3585 {
3586 inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged );
3587 }
3588
3589 // Force mDNS to update.
3590
3591 mDNSCoreMachineSleep( inMDNS, mDNSfalse );
3592 }
3593
3594
3595 //===========================================================================================================================
3596 // ProcessingThreadComputerDescriptionChanged
3597 //===========================================================================================================================
3598 mDNSlocal void ProcessingThreadComputerDescriptionChanged( mDNS *inMDNS )
3599 {
3600 mStatus err;
3601
3602 dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
3603 check( inMDNS );
3604
3605 mDNSPlatformLock( inMDNS );
3606
3607 // redo the names
3608 SetupNiceName( inMDNS );
3609
3610 if (inMDNS->p->hostDescriptionChangedCallback)
3611 {
3612 inMDNS->p->hostDescriptionChangedCallback(inMDNS);
3613 }
3614
3615 // and reset the event handler
3616 if ((inMDNS->p->descKey != NULL) && (inMDNS->p->descChangedEvent))
3617 {
3618 err = RegNotifyChangeKeyValue(inMDNS->p->descKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->descChangedEvent, TRUE);
3619 check_noerr( err );
3620 }
3621
3622 mDNSPlatformUnlock( inMDNS );
3623 }
3624
3625
3626 //===========================================================================================================================
3627 // ProcessingThreadTCPIPConfigChanged
3628 //===========================================================================================================================
3629 mDNSlocal void ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS )
3630 {
3631 mStatus err;
3632
3633 dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
3634 check( inMDNS );
3635
3636 mDNSPlatformLock( inMDNS );
3637
3638 err = dDNS_Setup( inMDNS );
3639 check_noerr( err );
3640
3641 // and reset the event handler
3642
3643 if ( ( inMDNS->p->tcpipKey != NULL ) && ( inMDNS->p->tcpipChangedEvent ) )
3644 {
3645 err = RegNotifyChangeKeyValue( inMDNS->p->tcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->tcpipChangedEvent, TRUE );
3646 check_noerr( err );
3647 }
3648
3649 mDNSPlatformUnlock( inMDNS );
3650 }
3651
3652
3653 //===========================================================================================================================
3654 // ProcessingThreadDynDNSConfigChanged
3655 //===========================================================================================================================
3656 mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
3657 {
3658 mStatus err;
3659
3660 dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
3661 check( inMDNS );
3662
3663 mDNSPlatformLock( inMDNS );
3664
3665 err = dDNS_Setup( inMDNS );
3666 check_noerr( err );
3667
3668 // and reset the event handler
3669
3670 if ((inMDNS->p->ddnsKey != NULL) && (inMDNS->p->ddnsChangedEvent))
3671 {
3672 err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
3673 check_noerr( err );
3674 }
3675
3676 mDNSPlatformUnlock( inMDNS );
3677 }
3678
3679
3680 #if 0
3681 #pragma mark -
3682 #pragma mark == Utilities ==
3683 #endif
3684
3685 //===========================================================================================================================
3686 // getifaddrs
3687 //===========================================================================================================================
3688
3689 int getifaddrs( struct ifaddrs **outAddrs )
3690 {
3691 int err;
3692
3693 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
3694
3695 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3696 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3697
3698 if( !gIPHelperLibraryInstance )
3699 {
3700 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
3701 if( gIPHelperLibraryInstance )
3702 {
3703 gGetAdaptersAddressesFunctionPtr =
3704 (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
3705 if( !gGetAdaptersAddressesFunctionPtr )
3706 {
3707 BOOL ok;
3708
3709 ok = FreeLibrary( gIPHelperLibraryInstance );
3710 check_translated_errno( ok, GetLastError(), kUnknownErr );
3711 gIPHelperLibraryInstance = NULL;
3712 }
3713 }
3714 }
3715
3716 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3717
3718 if( gGetAdaptersAddressesFunctionPtr )
3719 {
3720 err = getifaddrs_ipv6( outAddrs );
3721 require_noerr( err, exit );
3722 }
3723 else
3724 {
3725 err = getifaddrs_ipv4( outAddrs );
3726 require_noerr( err, exit );
3727 }
3728
3729 #elif( !TARGET_OS_WINDOWS_CE )
3730
3731 err = getifaddrs_ipv4( outAddrs );
3732 require_noerr( err, exit );
3733
3734 #else
3735
3736 err = getifaddrs_ce( outAddrs );
3737 require_noerr( err, exit );
3738
3739 #endif
3740
3741 exit:
3742 return( err );
3743 }
3744
3745 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3746 //===========================================================================================================================
3747 // getifaddrs_ipv6
3748 //===========================================================================================================================
3749
3750 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
3751 {
3752 DWORD err;
3753 int i;
3754 DWORD flags;
3755 struct ifaddrs * head;
3756 struct ifaddrs ** next;
3757 IP_ADAPTER_ADDRESSES * iaaList;
3758 ULONG iaaListSize;
3759 IP_ADAPTER_ADDRESSES * iaa;
3760 size_t size;
3761 struct ifaddrs * ifa;
3762
3763 check( gGetAdaptersAddressesFunctionPtr );
3764
3765 head = NULL;
3766 next = &head;
3767 iaaList = NULL;
3768
3769 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3770 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3771 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3772
3773 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
3774 i = 0;
3775 for( ;; )
3776 {
3777 iaaListSize = 0;
3778 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
3779 check( err == ERROR_BUFFER_OVERFLOW );
3780 check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
3781
3782 iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
3783 require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
3784
3785 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
3786 if( err == ERROR_SUCCESS ) break;
3787
3788 free( iaaList );
3789 iaaList = NULL;
3790 ++i;
3791 require( i < 100, exit );
3792 dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
3793 }
3794
3795 for( iaa = iaaList; iaa; iaa = iaa->Next )
3796 {
3797 int addrIndex;
3798 IP_ADAPTER_UNICAST_ADDRESS * addr;
3799 DWORD ipv6IfIndex;
3800 IP_ADAPTER_PREFIX * firstPrefix;
3801
3802 if( iaa->IfIndex > 0xFFFFFF )
3803 {
3804 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
3805 }
3806 if( iaa->Ipv6IfIndex > 0xFF )
3807 {
3808 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
3809 }
3810
3811 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3812 // following code to crash when iterating through the prefix list. This seems
3813 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3814 // This shouldn't happen according to Microsoft docs which states:
3815 //
3816 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3817 //
3818 // So the data structure seems to be corrupted when we return from
3819 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3820 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3821 // modify iaa to have the correct values.
3822
3823 if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
3824 {
3825 ipv6IfIndex = iaa->Ipv6IfIndex;
3826 firstPrefix = iaa->FirstPrefix;
3827 }
3828 else
3829 {
3830 ipv6IfIndex = 0;
3831 firstPrefix = NULL;
3832 }
3833
3834 // Skip psuedo and tunnel interfaces.
3835
3836 if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
3837 {
3838 continue;
3839 }
3840
3841 // Add each address as a separate interface to emulate the way getifaddrs works.
3842
3843 for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
3844 {
3845 int family;
3846 int prefixIndex;
3847 IP_ADAPTER_PREFIX * prefix;
3848 ULONG prefixLength;
3849
3850 family = addr->Address.lpSockaddr->sa_family;
3851 if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
3852
3853 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
3854 require_action( ifa, exit, err = WSAENOBUFS );
3855
3856 *next = ifa;
3857 next = &ifa->ifa_next;
3858
3859 // Get the name.
3860
3861 size = strlen( iaa->AdapterName ) + 1;
3862 ifa->ifa_name = (char *) malloc( size );
3863 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
3864 memcpy( ifa->ifa_name, iaa->AdapterName, size );
3865
3866 // Get interface flags.
3867
3868 ifa->ifa_flags = 0;
3869 if( iaa->OperStatus == IfOperStatusUp ) ifa->ifa_flags |= IFF_UP;
3870 if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK ) ifa->ifa_flags |= IFF_LOOPBACK;
3871 if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
3872
3873 // Get the interface index. Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes
3874 // so the following is a hack to put IPv4 interface indexes in the upper 24-bits and IPv6 interface indexes
3875 // in the lower 8-bits. This allows the IPv6 interface index to be usable as an IPv6 scope ID directly.
3876
3877 switch( family )
3878 {
3879 case AF_INET: ifa->ifa_extra.index = iaa->IfIndex << 8; break;
3880 case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex; break;
3881 default: break;
3882 }
3883
3884 // Get address.
3885
3886 switch( family )
3887 {
3888 case AF_INET:
3889 case AF_INET6:
3890 ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
3891 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
3892 memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
3893 break;
3894
3895 default:
3896 break;
3897 }
3898 check( ifa->ifa_addr );
3899
3900 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
3901
3902 prefixLength = 0;
3903 for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next )
3904 {
3905 if( prefixIndex == addrIndex )
3906 {
3907 check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" );
3908 prefixLength = prefix->PrefixLength;
3909 break;
3910 }
3911 }
3912 switch( family )
3913 {
3914 case AF_INET:
3915 {
3916 struct sockaddr_in * sa4;
3917
3918 require_action( prefixLength <= 32, exit, err = ERROR_INVALID_DATA );
3919
3920 sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
3921 require_action( sa4, exit, err = WSAENOBUFS );
3922
3923 sa4->sin_family = AF_INET;
3924 if( prefixLength == 0 )
3925 {
3926 dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv4 netmask 0, defaulting to 255.255.255.255\n", __ROUTINE__ );
3927 prefixLength = 32;
3928 }
3929 sa4->sin_addr.s_addr = htonl( 0xFFFFFFFFU << ( 32 - prefixLength ) );
3930 ifa->ifa_netmask = (struct sockaddr *) sa4;
3931 break;
3932 }
3933
3934 case AF_INET6:
3935 {
3936 struct sockaddr_in6 * sa6;
3937 int len;
3938 int maskIndex;
3939 uint8_t maskByte;
3940
3941 require_action( prefixLength <= 128, exit, err = ERROR_INVALID_DATA );
3942
3943 sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
3944 require_action( sa6, exit, err = WSAENOBUFS );
3945 sa6->sin6_family = AF_INET6;
3946
3947 if( prefixLength == 0 )
3948 {
3949 dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__ );
3950 prefixLength = 128;
3951 }
3952 maskIndex = 0;
3953 for( len = (int) prefixLength; len > 0; len -= 8 )
3954 {
3955 if( len >= 8 ) maskByte = 0xFF;
3956 else maskByte = (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
3957 sa6->sin6_addr.s6_addr[ maskIndex++ ] = maskByte;
3958 }
3959 ifa->ifa_netmask = (struct sockaddr *) sa6;
3960 break;
3961 }
3962
3963 default:
3964 break;
3965 }
3966 }
3967 }
3968
3969 // Success!
3970
3971 if( outAddrs )
3972 {
3973 *outAddrs = head;
3974 head = NULL;
3975 }
3976 err = ERROR_SUCCESS;
3977
3978 exit:
3979 if( head )
3980 {
3981 freeifaddrs( head );
3982 }
3983 if( iaaList )
3984 {
3985 free( iaaList );
3986 }
3987 return( (int) err );
3988 }
3989
3990 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
3991
3992 #if( !TARGET_OS_WINDOWS_CE )
3993 //===========================================================================================================================
3994 // getifaddrs_ipv4
3995 //===========================================================================================================================
3996
3997 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
3998 {
3999 int err;
4000 SOCKET sock;
4001 DWORD size;
4002 DWORD actualSize;
4003 INTERFACE_INFO * buffer;
4004 INTERFACE_INFO * tempBuffer;
4005 INTERFACE_INFO * ifInfo;
4006 int n;
4007 int i;
4008 struct ifaddrs * head;
4009 struct ifaddrs ** next;
4010 struct ifaddrs * ifa;
4011
4012 sock = INVALID_SOCKET;
4013 buffer = NULL;
4014 head = NULL;
4015 next = &head;
4016
4017 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
4018 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
4019 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
4020
4021 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
4022 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
4023 require_noerr( err, exit );
4024
4025 n = 0;
4026 size = 16 * sizeof( INTERFACE_INFO );
4027 for( ;; )
4028 {
4029 tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
4030 require_action( tempBuffer, exit, err = WSAENOBUFS );
4031 buffer = tempBuffer;
4032
4033 err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
4034 if( err == 0 )
4035 {
4036 break;
4037 }
4038
4039 ++n;
4040 require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
4041
4042 size += ( 16 * sizeof( INTERFACE_INFO ) );
4043 }
4044 check( actualSize <= size );
4045 check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
4046 n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
4047
4048 // Process the raw interface list and build a linked list of IPv4 interfaces.
4049
4050 for( i = 0; i < n; ++i )
4051 {
4052 ifInfo = &buffer[ i ];
4053 if( ifInfo->iiAddress.Address.sa_family != AF_INET )
4054 {
4055 continue;
4056 }
4057
4058 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
4059 require_action( ifa, exit, err = WSAENOBUFS );
4060
4061 *next = ifa;
4062 next = &ifa->ifa_next;
4063
4064 // Get the name.
4065
4066 ifa->ifa_name = (char *) malloc( 16 );
4067 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
4068 sprintf( ifa->ifa_name, "%d", i + 1 );
4069
4070 // Get interface flags.
4071
4072 ifa->ifa_flags = (u_int) ifInfo->iiFlags;
4073
4074 // Get addresses.
4075
4076 switch( ifInfo->iiAddress.Address.sa_family )
4077 {
4078 case AF_INET:
4079 {
4080 struct sockaddr_in * sa4;
4081
4082 sa4 = &ifInfo->iiAddress.AddressIn;
4083 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
4084 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
4085 memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
4086
4087 sa4 = &ifInfo->iiNetmask.AddressIn;
4088 ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
4089 require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
4090 memcpy( ifa->ifa_netmask, sa4, sizeof( *sa4 ) );
4091
4092 break;
4093 }
4094
4095 default:
4096 break;
4097 }
4098
4099 // Emulate an interface index.
4100
4101 ifa->ifa_extra.index = (uint32_t)( i + 1 );
4102 }
4103
4104 // Success!
4105
4106 if( outAddrs )
4107 {
4108 *outAddrs = head;
4109 head = NULL;
4110 }
4111 err = 0;
4112
4113 exit:
4114 if( head )
4115 {
4116 freeifaddrs( head );
4117 }
4118 if( buffer )
4119 {
4120 free( buffer );
4121 }
4122 if( sock != INVALID_SOCKET )
4123 {
4124 closesocket( sock );
4125 }
4126 return( err );
4127 }
4128 #endif // !TARGET_OS_WINDOWS_CE )
4129
4130 #if( TARGET_OS_WINDOWS_CE )
4131 //===========================================================================================================================
4132 // getifaddrs_ce
4133 //===========================================================================================================================
4134
4135 mDNSlocal int getifaddrs_ce( struct ifaddrs **outAddrs )
4136 {
4137 int err;
4138 SocketRef sock;
4139 DWORD size;
4140 void * buffer;
4141 SOCKET_ADDRESS_LIST * addressList;
4142 struct ifaddrs * head;
4143 struct ifaddrs ** next;
4144 struct ifaddrs * ifa;
4145 int n;
4146 int i;
4147
4148 sock = kInvalidSocketRef;
4149 buffer = NULL;
4150 head = NULL;
4151 next = &head;
4152
4153 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
4154
4155 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
4156 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
4157 require_noerr( err, exit );
4158
4159 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
4160 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
4161 //
4162 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
4163
4164 size = 0;
4165 WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL );
4166 require_action( size > 0, exit, err = -1 );
4167 size *= 2;
4168
4169 buffer = calloc( 1, size );
4170 require_action( buffer, exit, err = -1 );
4171
4172 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
4173
4174 err = WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, size, &size, NULL, NULL );
4175 require_noerr( err, exit );
4176 addressList = (SOCKET_ADDRESS_LIST *) buffer;
4177
4178 // Process the raw interface list and build a linked list of interfaces.
4179 //
4180 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
4181
4182 n = addressList->iAddressCount;
4183 if( n == 0 )
4184 {
4185 n = 1;
4186 }
4187 for( i = 0; i < n; ++i )
4188 {
4189 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
4190 require_action( ifa, exit, err = WSAENOBUFS );
4191
4192 *next = ifa;
4193 next = &ifa->ifa_next;
4194
4195 // Get the name.
4196
4197 ifa->ifa_name = (char *) malloc( 16 );
4198 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
4199 sprintf( ifa->ifa_name, "%d", i + 1 );
4200
4201 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
4202
4203 ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
4204
4205 // Get addresses.
4206
4207 switch( addressList->Address[ i ].lpSockaddr->sa_family )
4208 {
4209 case AF_INET:
4210 {
4211 struct sockaddr_in * sa4;
4212
4213 sa4 = (struct sockaddr_in *) addressList->Address[ i ].lpSockaddr;
4214 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
4215 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
4216 memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
4217 break;
4218 }
4219
4220 default:
4221 break;
4222 }
4223 }
4224
4225 // Success!
4226
4227 if( outAddrs )
4228 {
4229 *outAddrs = head;
4230 head = NULL;
4231 }
4232 err = 0;
4233
4234 exit:
4235 if( head )
4236 {
4237 freeifaddrs( head );
4238 }
4239 if( buffer )
4240 {
4241 free( buffer );
4242 }
4243 if( sock != INVALID_SOCKET )
4244 {
4245 closesocket( sock );
4246 }
4247 return( err );
4248 }
4249 #endif // TARGET_OS_WINDOWS_CE )
4250
4251 //===========================================================================================================================
4252 // freeifaddrs
4253 //===========================================================================================================================
4254
4255 void freeifaddrs( struct ifaddrs *inIFAs )
4256 {
4257 struct ifaddrs * p;
4258 struct ifaddrs * q;
4259
4260 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4261
4262 for( p = inIFAs; p; p = q )
4263 {
4264 q = p->ifa_next;
4265
4266 if( p->ifa_name )
4267 {
4268 free( p->ifa_name );
4269 p->ifa_name = NULL;
4270 }
4271 if( p->ifa_addr )
4272 {
4273 free( p->ifa_addr );
4274 p->ifa_addr = NULL;
4275 }
4276 if( p->ifa_netmask )
4277 {
4278 free( p->ifa_netmask );
4279 p->ifa_netmask = NULL;
4280 }
4281 if( p->ifa_broadaddr )
4282 {
4283 free( p->ifa_broadaddr );
4284 p->ifa_broadaddr = NULL;
4285 }
4286 if( p->ifa_dstaddr )
4287 {
4288 free( p->ifa_dstaddr );
4289 p->ifa_dstaddr = NULL;
4290 }
4291 if( p->ifa_data )
4292 {
4293 free( p->ifa_data );
4294 p->ifa_data = NULL;
4295 }
4296 free( p );
4297 }
4298 }
4299
4300 //===========================================================================================================================
4301 // CanReceiveUnicast
4302 //===========================================================================================================================
4303
4304 mDNSlocal mDNSBool CanReceiveUnicast( void )
4305 {
4306 mDNSBool ok;
4307 SocketRef sock;
4308 struct sockaddr_in addr;
4309
4310 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4311
4312 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
4313 check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
4314 ok = IsValidSocket( sock );
4315 if( ok )
4316 {
4317 memset( &addr, 0, sizeof( addr ) );
4318 addr.sin_family = AF_INET;
4319 addr.sin_port = MulticastDNSPort.NotAnInteger;
4320 addr.sin_addr.s_addr = htonl( INADDR_ANY );
4321
4322 ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
4323 close_compat( sock );
4324 }
4325
4326 dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
4327 return( ok );
4328 }
4329
4330 //===========================================================================================================================
4331 // GetWindowsVersionString
4332 //===========================================================================================================================
4333
4334 OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
4335 {
4336 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4337 #define VER_PLATFORM_WIN32_CE 3
4338 #endif
4339
4340 OSStatus err;
4341 OSVERSIONINFO osInfo;
4342 BOOL ok;
4343 const char * versionString;
4344 DWORD platformID;
4345 DWORD majorVersion;
4346 DWORD minorVersion;
4347 DWORD buildNumber;
4348
4349 versionString = "unknown Windows version";
4350
4351 osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
4352 ok = GetVersionEx( &osInfo );
4353 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
4354 require_noerr( err, exit );
4355
4356 platformID = osInfo.dwPlatformId;
4357 majorVersion = osInfo.dwMajorVersion;
4358 minorVersion = osInfo.dwMinorVersion;
4359 buildNumber = osInfo.dwBuildNumber & 0xFFFF;
4360
4361 if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
4362 {
4363 if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
4364 {
4365 versionString = "Windows 95";
4366 }
4367 else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
4368 {
4369 versionString = "Windows 95 SP1";
4370 }
4371 else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
4372 {
4373 versionString = "Windows 95 OSR2";
4374 }
4375 else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
4376 {
4377 versionString = "Windows 98";
4378 }
4379 else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
4380 {
4381 versionString = "Windows 98 SP1";
4382 }
4383 else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
4384 {
4385 versionString = "Windows 98 SE";
4386 }
4387 else if( minorVersion == 90 )
4388 {
4389 versionString = "Windows ME";
4390 }
4391 }
4392 else if( platformID == VER_PLATFORM_WIN32_NT )
4393 {
4394 if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
4395 {
4396 versionString = "Windows NT 3.51";
4397 }
4398 else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
4399 {
4400 versionString = "Windows NT 4";
4401 }
4402 else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
4403 {
4404 versionString = "Windows 2000";
4405 }
4406 else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
4407 {
4408 versionString = "Windows XP";
4409 }
4410 else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
4411 {
4412 versionString = "Windows Server 2003";
4413 }
4414 }
4415 else if( platformID == VER_PLATFORM_WIN32_CE )
4416 {
4417 versionString = "Windows CE";
4418 }
4419
4420 exit:
4421 if( inBuffer && ( inBufferSize > 0 ) )
4422 {
4423 inBufferSize -= 1;
4424 strncpy( inBuffer, versionString, inBufferSize );
4425 inBuffer[ inBufferSize ] = '\0';
4426 }
4427 return( err );
4428 }
4429
4430
4431 //===========================================================================================================================
4432 // RegQueryString
4433 //===========================================================================================================================
4434
4435 static mStatus
4436 RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
4437 {
4438 DWORD type;
4439 int i;
4440 mStatus err;
4441
4442 *stringLen = MAX_ESCAPED_DOMAIN_NAME;
4443 *string = NULL;
4444 i = 0;
4445
4446 do
4447 {
4448 if ( *string )
4449 {
4450 free( *string );
4451 }
4452
4453 *string = (char*) malloc( *stringLen );
4454 require_action( *string, exit, err = mStatus_NoMemoryErr );
4455
4456 err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
4457
4458 i++;
4459 }
4460 while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
4461
4462 require_noerr_quiet( err, exit );
4463
4464 if ( enabled )
4465 {
4466 DWORD dwSize = sizeof( DWORD );
4467
4468 err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
4469 check_noerr( err );
4470
4471 err = kNoErr;
4472 }
4473
4474 exit:
4475
4476 return err;
4477 }
4478
4479
4480 //===========================================================================================================================
4481 // StringToAddress
4482 //===========================================================================================================================
4483
4484 static mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
4485 {
4486 struct sockaddr_in6 sa6;
4487 struct sockaddr_in sa4;
4488 INT dwSize;
4489 mStatus err;
4490
4491 sa6.sin6_family = AF_INET6;
4492 dwSize = sizeof( sa6 );
4493
4494 err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
4495
4496 if ( err == mStatus_NoError )
4497 {
4498 err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa6 );
4499 require_noerr( err, exit );
4500 }
4501 else
4502 {
4503 sa4.sin_family = AF_INET;
4504 dwSize = sizeof( sa4 );
4505
4506 err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
4507 require_noerr( err, exit );
4508
4509 err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa4 );
4510 require_noerr( err, exit );
4511 }
4512
4513 exit:
4514
4515 return err;
4516 }
4517
4518
4519 //===========================================================================================================================
4520 // myGetIfAddrs
4521 //===========================================================================================================================
4522
4523 mDNSlocal struct ifaddrs*
4524 myGetIfAddrs(int refresh)
4525 {
4526 static struct ifaddrs *ifa = NULL;
4527
4528 if (refresh && ifa)
4529 {
4530 freeifaddrs(ifa);
4531 ifa = NULL;
4532 }
4533
4534 if (ifa == NULL)
4535 {
4536 getifaddrs(&ifa);
4537 }
4538
4539 return ifa;
4540 }
4541
4542
4543 //===========================================================================================================================
4544 // TCHARtoUTF8
4545 //===========================================================================================================================
4546
4547 mDNSlocal OSStatus
4548 TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
4549 {
4550 #if( defined( UNICODE ) || defined( _UNICODE ) )
4551 OSStatus err;
4552 int len;
4553
4554 len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
4555 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4556 require_noerr( err, exit );
4557
4558 exit:
4559 return( err );
4560 #else
4561 return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
4562 #endif
4563 }
4564
4565
4566 //===========================================================================================================================
4567 // WindowsLatin1toUTF8
4568 //===========================================================================================================================
4569
4570 mDNSlocal OSStatus
4571 WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
4572 {
4573 OSStatus err;
4574 WCHAR * utf16;
4575 int len;
4576
4577 utf16 = NULL;
4578
4579 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4580
4581 len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
4582 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4583 require_noerr( err, exit );
4584
4585 utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
4586 require_action( utf16, exit, err = kNoMemoryErr );
4587
4588 len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
4589 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4590 require_noerr( err, exit );
4591
4592 // Now convert the temporary UTF-16 to UTF-8.
4593
4594 len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
4595 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4596 require_noerr( err, exit );
4597
4598 exit:
4599 if( utf16 ) free( utf16 );
4600 return( err );
4601 }
4602
4603
4604 //===========================================================================================================================
4605 // ConvertUTF8ToLsaString
4606 //===========================================================================================================================
4607
4608 mDNSlocal OSStatus
4609 ConvertUTF8ToLsaString( const char * input, PLSA_UNICODE_STRING output )
4610 {
4611 int size;
4612 OSStatus err;
4613
4614 check( input );
4615 check( output );
4616
4617 output->Buffer = NULL;
4618
4619 size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 );
4620 err = translate_errno( size > 0, GetLastError(), kUnknownErr );
4621 require_noerr( err, exit );
4622
4623 output->Length = (USHORT)( size * sizeof( wchar_t ) );
4624 output->Buffer = (PWCHAR) malloc( output->Length );
4625 require_action( output->Buffer, exit, err = mStatus_NoMemoryErr );
4626 size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size );
4627 err = translate_errno( size > 0, GetLastError(), kUnknownErr );
4628 require_noerr( err, exit );
4629
4630 // We're going to subtrace one wchar_t from the size, because we didn't
4631 // include it when we encoded the string
4632
4633 output->MaximumLength = output->Length;
4634 output->Length -= sizeof( wchar_t );
4635
4636 exit:
4637
4638 if ( err && output->Buffer )
4639 {
4640 free( output->Buffer );
4641 output->Buffer = NULL;
4642 }
4643
4644 return( err );
4645 }
4646
4647
4648 //===========================================================================================================================
4649 // ConvertLsaStringToUTF8
4650 //===========================================================================================================================
4651
4652 static OSStatus
4653 ConvertLsaStringToUTF8( PLSA_UNICODE_STRING input, char ** output )
4654 {
4655 int size;
4656 OSStatus err = kNoErr;
4657
4658 // The Length field of this structure holds the number of bytes,
4659 // but WideCharToMultiByte expects the number of wchar_t's. So
4660 // we divide by sizeof(wchar_t) to get the correct number.
4661
4662 size = WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL);
4663 err = translate_errno( size != 0, GetLastError(), kUnknownErr );
4664 require_noerr( err, exit );
4665
4666 // Add one for trailing '\0'
4667
4668 *output = (char*) malloc( size + 1 );
4669 require_action( *output, exit, err = mStatus_NoMemoryErr );
4670
4671 size = WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), *output, size, NULL, NULL);
4672 err = translate_errno( size != 0, GetLastError(), kUnknownErr );
4673 require_noerr( err, exit );
4674
4675 // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
4676 // although it does return the correct size
4677
4678 (*output)[size] = '\0';
4679
4680 exit:
4681
4682 if ( err && *output )
4683 {
4684 free( *output );
4685 *output = NULL;
4686 }
4687
4688 return err;
4689 }
4690
4691
4692 //===========================================================================================================================
4693 // FreeTCPConnectionData
4694 //===========================================================================================================================
4695
4696 mDNSlocal void
4697 FreeTCPConnectionData( mDNSTCPConnectionData * data )
4698 {
4699 check( data );
4700
4701 if ( data->pendingEvent )
4702 {
4703 CloseHandle( data->pendingEvent );
4704 }
4705
4706 if ( data->sock != INVALID_SOCKET )
4707 {
4708 closesocket( data->sock );
4709 }
4710
4711 free( data );
4712 }