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