]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/mDNSWin32.c
b24527fa12d4bcf8df6f2f51567bc75ccb6f780d
[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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: mDNSWin32.c,v $
28 Revision 1.40 2004/05/26 09:06:07 bradley
29 Retry while building the interface list if it returns an error since the two-step process required to
30 get the interface list could allow a subsequent interface change to come in that window and change the
31 needed size after getting the size, but before getting the list, causing it to return an error.
32 Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
33
34 Revision 1.39 2004/05/18 23:51:27 cheshire
35 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
36
37 Revision 1.38 2004/05/13 04:57:48 ksekar
38 Removed unnecessary FreeSearchList function
39
40 Revision 1.37 2004/05/13 04:54:20 ksekar
41 Unified list copy/free code. Added symetric list for
42
43 Revision 1.36 2004/05/12 22:03:09 ksekar
44 Made GetSearchDomainList a true platform-layer call (declaration moved
45 from mDNSMacOSX.h to mDNSClientAPI.h), impelemted to return "local"
46 only on non-OSX platforms. Changed call to return a copy of the list
47 to avoid shared memory issues. Added a routine to free the list.
48
49 Revision 1.35 2004/04/21 02:49:12 cheshire
50 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
51
52 Revision 1.34 2004/04/15 01:00:05 bradley
53 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
54 without .local name resolving support will need to manually query for A/AAAA records as needed.
55
56 Revision 1.33 2004/04/14 23:09:29 ksekar
57 Support for TSIG signed dynamic updates.
58
59 Revision 1.32 2004/04/09 17:40:26 cheshire
60 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
61
62 Revision 1.31 2004/04/09 00:40:46 bradley
63 Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
64
65 Revision 1.30 2004/04/09 00:33:58 bradley
66 Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
67
68 Revision 1.29 2004/03/15 02:07:46 bradley
69 Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
70 handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
71 does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
72
73 Revision 1.28 2004/03/07 00:26:39 bradley
74 Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
75 Added count assert when building the wait list to catch underruns/overruns if the code is changed.
76
77 Revision 1.27 2004/01/30 02:44:32 bradley
78 Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
79 InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
80 are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
81 (it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
82 software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
83 reporting HINFO records with the Windows and mDNSResponder version information.
84
85 Revision 1.26 2004/01/24 04:59:16 cheshire
86 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
87
88 Revision 1.25 2003/11/14 20:59:09 cheshire
89 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
90 Best solution is just to combine mDNSClientAPI.h and mDNSPlatformFunctions.h into a single file.
91
92 Revision 1.24 2003/10/24 23:23:02 bradley
93 Removed legacy port 53 support as it is no longer needed.
94
95 Revision 1.23 2003/10/14 03:26:12 bradley
96 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
97
98 Revision 1.22 2003/08/20 06:21:25 bradley
99 Updated to latest internal version of the Rendezvous for Windows platform plugin: Added support
100 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
101 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
102 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
103 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
104 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
105 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
106 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
107 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
108
109 Revision 1.21 2003/08/18 23:09:57 cheshire
110 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
111
112 Revision 1.20 2003/08/12 19:56:27 cheshire
113 Update to APSL 2.0
114
115 Revision 1.19 2003/08/05 23:58:18 cheshire
116 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
117 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
118
119 Revision 1.18 2003/07/23 21:16:30 cheshire
120 Removed a couple of debugfs
121
122 Revision 1.17 2003/07/23 02:23:01 cheshire
123 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
124 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
125
126 Revision 1.16 2003/07/19 03:15:16 cheshire
127 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
128 and add the obvious trivial implementations to each platform support layer
129
130 Revision 1.15 2003/07/02 21:20:04 cheshire
131 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
132
133 Revision 1.14 2003/05/26 03:21:30 cheshire
134 Tidy up address structure naming:
135 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
136 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
137 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
138
139 Revision 1.13 2003/05/26 03:01:28 cheshire
140 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
141
142 Revision 1.12 2003/05/06 21:06:05 cheshire
143 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
144
145 Revision 1.11 2003/05/06 00:00:51 cheshire
146 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
147
148 Revision 1.10 2003/04/29 00:06:09 cheshire
149 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
150
151 Revision 1.9 2003/04/26 02:40:01 cheshire
152 Add void LogMsg( const char *format, ... )
153
154 Revision 1.8 2003/03/22 02:57:44 cheshire
155 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
156
157 Revision 1.7 2003/03/15 04:40:38 cheshire
158 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
159
160 Revision 1.6 2003/02/21 01:54:10 cheshire
161 <rdar://problem/3099194> mDNSResponder needs performance improvements
162 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
163
164 Revision 1.5 2003/02/20 00:59:03 cheshire
165 Brought Windows code up to date so it complies with
166 Josh Graessley's interface changes for IPv6 support.
167 (Actual support for IPv6 on Windows will come later.)
168
169 Revision 1.4 2002/09/21 20:44:54 zarzycki
170 Added APSL info
171
172 Revision 1.3 2002/09/20 05:50:45 bradley
173 Multicast DNS platform plugin for Win32
174
175 To Do:
176
177 - Get unicode name of machine for nice name instead of just the host name.
178 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
179 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
180 - Implement TCP support for truncated packets (only stubs now).
181 */
182
183 #include <stdarg.h>
184 #include <stddef.h>
185 #include <stdio.h>
186 #include <stdlib.h>
187 #include <string.h>
188
189 #include "CommonServices.h"
190 #include "DebugServices.h"
191
192 #include <Iphlpapi.h>
193 #if( !TARGET_OS_WINDOWS_CE )
194 #include <mswsock.h>
195 #include <process.h>
196 #endif
197
198 #include "mDNSClientAPI.h"
199
200 #include "mDNSWin32.h"
201
202 #if 0
203 #pragma mark == Constants ==
204 #endif
205
206 //===========================================================================================================================
207 // Constants
208 //===========================================================================================================================
209
210 #define DEBUG_NAME "[mDNSWin32] "
211
212 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
213 #define MDNS_WINDOWS_ENABLE_IPV4 1
214 #define MDNS_WINDOWS_ENABLE_IPV6 1
215 #define MDNS_WINDOWS_EXCLUDE_IPV4_ROUTABLE_IPV6 1
216 #define MDNS_WINDOWS_AAAA_OVER_IPV4 1
217
218 #define kMDNSDefaultName "My Computer"
219
220 #define kWinSockMajorMin 2
221 #define kWinSockMinorMin 2
222
223 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
224 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
225 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
226 #define kWaitListFixedItemCount 3
227
228 #if( !TARGET_OS_WINDOWS_CE )
229 static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
230 #endif
231
232 #if 0
233 #pragma mark == Prototypes ==
234 #endif
235
236 //===========================================================================================================================
237 // Prototypes
238 //===========================================================================================================================
239
240 mDNSlocal mStatus SetupSynchronizationObjects( mDNS * const inMDNS );
241 mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS );
242 mDNSlocal mStatus SetupName( mDNS * const inMDNS );
243 mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS );
244 mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS );
245 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
246 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
247 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, SocketRef *outSocketRef );
248 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
249 mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS );
250 mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS );
251
252 mDNSlocal mStatus SetupThread( mDNS * const inMDNS );
253 mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS );
254 mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam );
255 mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS );
256 mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
257 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock );
258 mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
259
260 // Platform Accessors
261
262 #ifdef __cplusplus
263 extern "C" {
264 #endif
265
266 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
267 struct mDNSPlatformInterfaceInfo
268 {
269 const char * name;
270 mDNSAddr ip;
271 };
272
273 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
274 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
275
276 // Utilities
277
278 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
279 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
280 #endif
281
282 #if( !TARGET_OS_WINDOWS_CE )
283 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
284 #endif
285
286 #if( TARGET_OS_WINDOWS_CE )
287 mDNSlocal int getifaddrs_ce( struct ifaddrs **outAddrs );
288 #endif
289
290 mDNSlocal mDNSBool CanReceiveUnicast( void );
291 mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
292
293 #ifdef __cplusplus
294 }
295 #endif
296
297 #if 0
298 #pragma mark == Globals ==
299 #endif
300
301 //===========================================================================================================================
302 // Globals
303 //===========================================================================================================================
304
305 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
306 mDNSs32 mDNSPlatformOneSecond = 0;
307
308 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
309
310 typedef DWORD
311 ( WINAPI * GetAdaptersAddressesFunctionPtr )(
312 ULONG inFamily,
313 DWORD inFlags,
314 PVOID inReserved,
315 PIP_ADAPTER_ADDRESSES inAdapter,
316 PULONG outBufferSize );
317
318 mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
319 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
320
321 #endif
322
323 #if 0
324 #pragma mark -
325 #pragma mark == Platform Support ==
326 #endif
327
328 //===========================================================================================================================
329 // mDNSPlatformInit
330 //===========================================================================================================================
331
332 mStatus mDNSPlatformInit( mDNS * const inMDNS )
333 {
334 mStatus err;
335 WSADATA wsaData;
336 int supported;
337
338 dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
339
340 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
341 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
342
343 memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
344 if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
345 inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
346 mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
347
348 // Startup WinSock 2.2 or later.
349
350 err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
351 require_noerr( err, exit );
352
353 supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
354 require_action( supported, exit, err = mStatus_UnsupportedErr );
355
356 inMDNS->CanReceiveUnicast = CanReceiveUnicast();
357
358 // Setup the HINFO HW/SW strings.
359
360 err = GetWindowsVersionString( (char *) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2 );
361 check_noerr( err );
362 inMDNS->HIHardware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
363 dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
364
365 mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
366 "mDNSResponder (%s %s)", __DATE__, __TIME__ );
367 inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
368 dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
369
370 // Set up the mDNS thread.
371
372 err = SetupSynchronizationObjects( inMDNS );
373 require_noerr( err, exit );
374
375 err = SetupThread( inMDNS );
376 require_noerr( err, exit );
377
378 // Success!
379
380 mDNSCoreInitComplete( inMDNS, err );
381
382 exit:
383 if( err )
384 {
385 mDNSPlatformClose( inMDNS );
386 }
387 dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
388 return( err );
389 }
390
391 //===========================================================================================================================
392 // mDNSPlatformClose
393 //===========================================================================================================================
394
395 void mDNSPlatformClose( mDNS * const inMDNS )
396 {
397 mStatus err;
398
399 dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
400 check( inMDNS );
401
402 // Tear everything down in reverse order to how it was set up.
403
404 err = TearDownThread( inMDNS );
405 check_noerr( err );
406
407 err = TearDownInterfaceList( inMDNS );
408 check_noerr( err );
409
410 err = TearDownSynchronizationObjects( inMDNS );
411 check_noerr( err );
412
413 // Free the DLL needed for IPv6 support.
414
415 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
416 if( gIPHelperLibraryInstance )
417 {
418 gGetAdaptersAddressesFunctionPtr = NULL;
419
420 FreeLibrary( gIPHelperLibraryInstance );
421 gIPHelperLibraryInstance = NULL;
422 }
423 #endif
424
425 WSACleanup();
426
427 dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
428 }
429
430 //===========================================================================================================================
431 // mDNSPlatformSendUDP
432 //===========================================================================================================================
433
434 mStatus
435 mDNSPlatformSendUDP(
436 const mDNS * const inMDNS,
437 const DNSMessage * const inMsg,
438 const mDNSu8 * const inMsgEnd,
439 mDNSInterfaceID inInterfaceID,
440 const mDNSAddr * inDstIP,
441 mDNSIPPort inDstPort )
442 {
443 mStatus err;
444 mDNSInterfaceData * ifd;
445 struct sockaddr_storage addr;
446 int n;
447
448 DEBUG_USE_ONLY( inMDNS );
449
450 n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
451 check( inMDNS );
452 check( inMsg );
453 check( inMsgEnd );
454 check( inInterfaceID );
455 check( inDstIP );
456
457 ifd = (mDNSInterfaceData *) inInterfaceID;
458 require_action_quiet( ifd->interfaceInfo.McastTxRx, exit, err = mStatus_Invalid ); // Silent Interface
459 require_action_quiet( inDstIP->type == ifd->interfaceInfo.ip.type, exit, err = mStatus_NoError ); // Wrong Type
460 check( IsValidSocket( ifd->sock ) );
461
462 dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
463
464 if( inDstIP->type == mDNSAddrType_IPv4 )
465 {
466 struct sockaddr_in * sa4;
467
468 sa4 = (struct sockaddr_in *) &addr;
469 sa4->sin_family = AF_INET;
470 sa4->sin_port = inDstPort.NotAnInteger;
471 sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
472 }
473 else if( inDstIP->type == mDNSAddrType_IPv6 )
474 {
475 struct sockaddr_in6 * sa6;
476
477 sa6 = (struct sockaddr_in6 *) &addr;
478 sa6->sin6_family = AF_INET6;
479 sa6->sin6_port = inDstPort.NotAnInteger;
480 sa6->sin6_flowinfo = 0;
481 sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
482 sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
483 }
484 else
485 {
486 dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
487 err = mStatus_BadParamErr;
488 goto exit;
489 }
490
491 n = sendto( ifd->sock, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
492 err = translate_errno( n > 0, errno_compat(), kWriteErr );
493 require_noerr( err, exit );
494
495 exit:
496 return( err );
497 }
498
499 //===========================================================================================================================
500 // mDNSPlatformLock
501 //===========================================================================================================================
502
503 void mDNSPlatformLock( const mDNS * const inMDNS )
504 {
505 check( inMDNS );
506 check( inMDNS->p->lockInitialized );
507
508 EnterCriticalSection( &inMDNS->p->lock );
509 }
510
511 //===========================================================================================================================
512 // mDNSPlatformUnlock
513 //===========================================================================================================================
514
515 void mDNSPlatformUnlock( const mDNS * const inMDNS )
516 {
517 check( inMDNS );
518 check( inMDNS->p );
519 check( inMDNS->p->lockInitialized );
520 check( inMDNS->p->threadID );
521
522 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
523 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
524
525 if( GetCurrentThreadId() != inMDNS->p->threadID )
526 {
527 BOOL wasSet;
528
529 wasSet = SetEvent( inMDNS->p->wakeupEvent );
530 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
531 }
532 LeaveCriticalSection( &inMDNS->p->lock );
533 }
534
535 //===========================================================================================================================
536 // mDNSPlatformStrCopy
537 //===========================================================================================================================
538
539 void mDNSPlatformStrCopy( const void *inSrc, void *inDst )
540 {
541 check( inSrc );
542 check( inDst );
543
544 strcpy( (char *) inDst, (const char*) inSrc );
545 }
546
547 //===========================================================================================================================
548 // mDNSPlatformStrLen
549 //===========================================================================================================================
550
551 mDNSu32 mDNSPlatformStrLen( const void *inSrc )
552 {
553 check( inSrc );
554
555 return( (mDNSu32) strlen( (const char *) inSrc ) );
556 }
557
558 //===========================================================================================================================
559 // mDNSPlatformMemCopy
560 //===========================================================================================================================
561
562 void mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
563 {
564 check( inSrc );
565 check( inDst );
566
567 memcpy( inDst, inSrc, inSize );
568 }
569
570 //===========================================================================================================================
571 // mDNSPlatformMemSame
572 //===========================================================================================================================
573
574 mDNSBool mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
575 {
576 check( inSrc );
577 check( inDst );
578
579 return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
580 }
581
582 //===========================================================================================================================
583 // mDNSPlatformMemZero
584 //===========================================================================================================================
585
586 void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
587 {
588 check( inDst );
589
590 memset( inDst, 0, inSize );
591 }
592
593 //===========================================================================================================================
594 // mDNSPlatformMemAllocate
595 //===========================================================================================================================
596
597 mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
598 {
599 void * mem;
600
601 check( inSize > 0 );
602
603 mem = malloc( inSize );
604 check( mem );
605
606 return( mem );
607 }
608
609 //===========================================================================================================================
610 // mDNSPlatformMemFree
611 //===========================================================================================================================
612
613 mDNSexport void mDNSPlatformMemFree( void *inMem )
614 {
615 check( inMem );
616
617 free( inMem );
618 }
619
620 //===========================================================================================================================
621 // mDNSPlatformTimeInit
622 //===========================================================================================================================
623
624 mDNSexport mStatus mDNSPlatformTimeInit( mDNSs32 *outTimeNow )
625 {
626 check( outTimeNow );
627
628 // No special setup is required on Windows -- we just use GetTickCount().
629
630 *outTimeNow = mDNSPlatformTimeNow();
631 return( mStatus_NoError );
632 }
633
634 //===========================================================================================================================
635 // mDNSPlatformTimeNow
636 //===========================================================================================================================
637
638 mDNSs32 mDNSPlatformTimeNow( void )
639 {
640 return( (mDNSs32) GetTickCount() );
641 }
642
643 //===========================================================================================================================
644 // mDNSPlatformUTC
645 //===========================================================================================================================
646
647 mDNSexport mDNSs32 mDNSPlatformUTC( void )
648 {
649 return( -1 );
650 }
651
652 //===========================================================================================================================
653 // mDNSPlatformInterfaceNameToID
654 //===========================================================================================================================
655
656 mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
657 {
658 mStatus err;
659 mDNSInterfaceData * ifd;
660
661 check( inMDNS );
662 check( inMDNS->p );
663 check( inName );
664
665 // Search for an interface with the specified name,
666
667 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
668 {
669 if( strcmp( ifd->name, inName ) == 0 )
670 {
671 break;
672 }
673 }
674 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
675
676 // Success!
677
678 if( outID )
679 {
680 *outID = (mDNSInterfaceID) ifd;
681 }
682 err = mStatus_NoError;
683
684 exit:
685 return( err );
686 }
687
688 //===========================================================================================================================
689 // mDNSPlatformInterfaceIDToInfo
690 //===========================================================================================================================
691
692 mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
693 {
694 mStatus err;
695 mDNSInterfaceData * ifd;
696
697 check( inMDNS );
698 check( inID );
699 check( outInfo );
700
701 // Search for an interface with the specified ID,
702
703 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
704 {
705 if( ifd == (mDNSInterfaceData *) inID )
706 {
707 break;
708 }
709 }
710 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
711
712 // Success!
713
714 outInfo->name = ifd->name;
715 outInfo->ip = ifd->interfaceInfo.ip;
716 err = mStatus_NoError;
717
718 exit:
719 return( err );
720 }
721
722 //===========================================================================================================================
723 // mDNSPlatformInterfaceIDfromInterfaceIndex
724 //===========================================================================================================================
725
726 mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const inMDNS, mDNSu32 inIndex )
727 {
728 mDNSInterfaceID id;
729
730 id = mDNSNULL;
731 if( inIndex == (mDNSu32) ~0 )
732 {
733 id = mDNSInterface_LocalOnly;
734 }
735 else if( inIndex != 0 )
736 {
737 mDNSInterfaceData * ifd;
738
739 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
740 {
741 if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
742 {
743 id = ifd->interfaceInfo.InterfaceID;
744 break;
745 }
746 }
747 check( ifd );
748 }
749 return( id );
750 }
751
752 //===========================================================================================================================
753 // mDNSPlatformInterfaceIndexfromInterfaceID
754 //===========================================================================================================================
755
756 mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mDNSInterfaceID inID )
757 {
758 mDNSu32 index;
759
760 index = 0;
761 if( inID == mDNSInterface_LocalOnly )
762 {
763 index = (mDNSu32) ~0;
764 }
765 else if( inID )
766 {
767 mDNSInterfaceData * ifd;
768
769 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
770 {
771 if( (mDNSInterfaceID) ifd == inID )
772 {
773 index = ifd->scopeID;
774 break;
775 }
776 }
777 check( ifd );
778 }
779 return( index );
780 }
781
782 //===========================================================================================================================
783 // mDNSPlatformTCPConnect
784 //===========================================================================================================================
785
786 mStatus
787 mDNSPlatformTCPConnect(
788 const mDNSAddr * inDstIP,
789 mDNSOpaque16 inDstPort,
790 mDNSInterfaceID inInterfaceID,
791 TCPConnectionCallback inCallback,
792 void * inContext,
793 int * outSock )
794 {
795 DEBUG_UNUSED( inDstIP );
796 DEBUG_UNUSED( inDstPort );
797 DEBUG_UNUSED( inInterfaceID );
798 DEBUG_UNUSED( inCallback );
799 DEBUG_UNUSED( inContext );
800 DEBUG_UNUSED( outSock );
801
802 return( mStatus_UnsupportedErr );
803 }
804
805 //===========================================================================================================================
806 // mDNSPlatformTCPCloseConnection
807 //===========================================================================================================================
808
809 void mDNSPlatformTCPCloseConnection( int inSock )
810 {
811 DEBUG_UNUSED( inSock );
812 }
813
814 //===========================================================================================================================
815 // mDNSPlatformReadTCP
816 //===========================================================================================================================
817
818 int mDNSPlatformReadTCP( int inSock, void *inBuffer, int inBufferSize )
819 {
820 DEBUG_UNUSED( inSock );
821 DEBUG_UNUSED( inBuffer );
822 DEBUG_UNUSED( inBufferSize );
823
824 return( -1 );
825 }
826
827 //===========================================================================================================================
828 // mDNSPlatformWriteTCP
829 //===========================================================================================================================
830
831 int mDNSPlatformWriteTCP( int inSock, const char *inMsg, int inMsgSize )
832 {
833 DEBUG_UNUSED( inSock );
834 DEBUG_UNUSED( inMsg );
835 DEBUG_UNUSED( inMsgSize );
836
837 return( -1 );
838 }
839
840
841 //===========================================================================================================================
842 // mDNSPlatformGetSearchDomainList
843 //===========================================================================================================================
844
845
846 mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
847 {
848 static DNameListElem tmp;
849 static int init = 0;
850
851 if (!init)
852 {
853 MakeDomainNameFromDNSNameString(&tmp.name, "local.");
854 tmp.next = NULL;
855 init = 1;
856 }
857 return mDNS_CopyDNameList(&tmp);
858 }
859
860
861
862 #if 0
863 #pragma mark -
864 #endif
865
866 //===========================================================================================================================
867 // debugf_
868 //===========================================================================================================================
869
870 #if( MDNS_DEBUGMSGS )
871 void debugf_( const char *inFormat, ... )
872 {
873 char buffer[ 512 ];
874 va_list args;
875 mDNSu32 length;
876
877 va_start( args, inFormat );
878 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
879 va_end( args );
880
881 dlog( kDebugLevelInfo, "%s\n", buffer );
882 }
883 #endif
884
885 //===========================================================================================================================
886 // verbosedebugf_
887 //===========================================================================================================================
888
889 #if( MDNS_DEBUGMSGS > 1 )
890 void verbosedebugf_( const char *inFormat, ... )
891 {
892 char buffer[ 512 ];
893 va_list args;
894 mDNSu32 length;
895
896 va_start( args, inFormat );
897 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
898 va_end( args );
899
900 dlog( kDebugLevelVerbose, "%s\n", buffer );
901 }
902 #endif
903
904 //===========================================================================================================================
905 // LogMsg
906 //===========================================================================================================================
907
908 void LogMsg( const char *inFormat, ... )
909 {
910 char buffer[ 512 ];
911 va_list args;
912 mDNSu32 length;
913
914 va_start( args, inFormat );
915 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
916 va_end( args );
917
918 dlog( kDebugLevelWarning, "%s\n", buffer );
919 }
920
921 #if 0
922 #pragma mark -
923 #pragma mark == Platform Internals ==
924 #endif
925
926 //===========================================================================================================================
927 // SetupSynchronizationObjects
928 //===========================================================================================================================
929
930 mDNSlocal mStatus SetupSynchronizationObjects( mDNS * const inMDNS )
931 {
932 mStatus err;
933
934 InitializeCriticalSection( &inMDNS->p->lock );
935 inMDNS->p->lockInitialized = mDNStrue;
936
937 inMDNS->p->cancelEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
938 err = translate_errno( inMDNS->p->cancelEvent, (mStatus) GetLastError(), kUnknownErr );
939 require_noerr( err, exit );
940
941 inMDNS->p->quitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
942 err = translate_errno( inMDNS->p->quitEvent, (mStatus) GetLastError(), kUnknownErr );
943 require_noerr( err, exit );
944
945 inMDNS->p->interfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
946 err = translate_errno( inMDNS->p->interfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
947 require_noerr( err, exit );
948
949 inMDNS->p->wakeupEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
950 err = translate_errno( inMDNS->p->wakeupEvent, (mStatus) GetLastError(), kUnknownErr );
951 require_noerr( err, exit );
952
953 exit:
954 if( err )
955 {
956 TearDownSynchronizationObjects( inMDNS );
957 }
958 return( err );
959 }
960
961 //===========================================================================================================================
962 // TearDownSynchronizationObjects
963 //===========================================================================================================================
964
965 mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS )
966 {
967 if( inMDNS->p->quitEvent )
968 {
969 CloseHandle( inMDNS->p->quitEvent );
970 inMDNS->p->quitEvent = 0;
971 }
972 if( inMDNS->p->cancelEvent )
973 {
974 CloseHandle( inMDNS->p->cancelEvent );
975 inMDNS->p->cancelEvent = 0;
976 }
977 if( inMDNS->p->interfaceListChangedEvent )
978 {
979 CloseHandle( inMDNS->p->interfaceListChangedEvent );
980 inMDNS->p->interfaceListChangedEvent = 0;
981 }
982 if( inMDNS->p->wakeupEvent )
983 {
984 CloseHandle( inMDNS->p->wakeupEvent );
985 inMDNS->p->wakeupEvent = 0;
986 }
987 if( inMDNS->p->lockInitialized )
988 {
989 DeleteCriticalSection( &inMDNS->p->lock );
990 inMDNS->p->lockInitialized = mDNSfalse;
991 }
992 return( mStatus_NoError );
993 }
994
995 //===========================================================================================================================
996 // SetupName
997 //===========================================================================================================================
998
999 mDNSlocal mStatus SetupName( mDNS * const inMDNS )
1000 {
1001 mStatus err;
1002 char tempString[ 256 ];
1003
1004 check( inMDNS );
1005
1006 // Set up the nice name.
1007
1008 tempString[ 0 ] = '\0';
1009 err = gethostname( tempString, sizeof( tempString ) - 1 );
1010 check_translated_errno( err == 0, errno_compat(), kNameErr );
1011 if( err || ( tempString[ 0 ] == '\0' ) )
1012 {
1013 // Invalidate name so fall back to a default name.
1014
1015 strcpy( tempString, kMDNSDefaultName );
1016 }
1017 tempString[ sizeof( tempString ) - 1 ] = '\0';
1018
1019 inMDNS->nicelabel.c[ 0 ] = (mDNSu8) strlen( tempString );
1020 memcpy( &inMDNS->nicelabel.c[ 1 ], tempString, inMDNS->nicelabel.c[ 0 ] );
1021
1022 // Set up the host name.
1023
1024 ConvertUTF8PstringToRFC1034HostLabel( inMDNS->nicelabel.c, &inMDNS->hostlabel );
1025 if( inMDNS->hostlabel.c[ 0 ] == 0 )
1026 {
1027 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
1028
1029 MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
1030 }
1031 check( inMDNS->nicelabel.c[ 0 ] != 0 );
1032 check( inMDNS->hostlabel.c[ 0 ] != 0 );
1033
1034 mDNS_GenerateFQDN( inMDNS );
1035
1036 dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
1037 dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
1038 return( err );
1039 }
1040
1041 //===========================================================================================================================
1042 // SetupInterfaceList
1043 //===========================================================================================================================
1044
1045 mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
1046 {
1047 mStatus err;
1048 mDNSInterfaceData ** next;
1049 mDNSInterfaceData * ifd;
1050 struct ifaddrs * addrs;
1051 struct ifaddrs * p;
1052 struct ifaddrs * loopback;
1053 u_int flagMask;
1054 u_int flagTest;
1055
1056 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
1057 check( inMDNS );
1058 check( inMDNS->p );
1059
1060 addrs = NULL;
1061
1062 // Tear down any existing interfaces that may be set up.
1063
1064 TearDownInterfaceList( inMDNS );
1065
1066 // Set up the name of this machine.
1067
1068 err = SetupName( inMDNS );
1069 check_noerr( err );
1070
1071 // Set up the interface list change notification.
1072
1073 err = SetupNotifications( inMDNS );
1074 check_noerr( err );
1075
1076 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
1077 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
1078
1079 err = getifaddrs( &addrs );
1080 require_noerr( err, exit );
1081
1082 loopback = NULL;
1083 next = &inMDNS->p->interfaceList;
1084
1085 flagMask = IFF_UP | IFF_MULTICAST | IFF_POINTTOPOINT;
1086 flagTest = IFF_UP | IFF_MULTICAST;
1087
1088 #if( MDNS_WINDOWS_ENABLE_IPV4 )
1089 for( p = addrs; p; p = p->ifa_next )
1090 {
1091 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
1092 {
1093 continue;
1094 }
1095 if( p->ifa_flags & IFF_LOOPBACK )
1096 {
1097 if( !loopback )
1098 {
1099 loopback = p;
1100 }
1101 continue;
1102 }
1103 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
1104 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
1105
1106 err = SetupInterface( inMDNS, p, &ifd );
1107 require_noerr( err, exit );
1108
1109 *next = ifd;
1110 next = &ifd->next;
1111 ++inMDNS->p->interfaceCount;
1112 }
1113 #endif
1114
1115 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
1116
1117 #if( MDNS_WINDOWS_ENABLE_IPV6 )
1118 for( p = addrs; p; p = p->ifa_next )
1119 {
1120 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
1121 {
1122 continue;
1123 }
1124 if( p->ifa_flags & IFF_LOOPBACK )
1125 {
1126 if( !loopback )
1127 {
1128 loopback = p;
1129 }
1130 continue;
1131 }
1132 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
1133 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
1134
1135 err = SetupInterface( inMDNS, p, &ifd );
1136 require_noerr( err, exit );
1137
1138 *next = ifd;
1139 next = &ifd->next;
1140 ++inMDNS->p->interfaceCount;
1141 }
1142 #endif
1143
1144 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
1145
1146 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
1147
1148 flagMask |= IFF_LOOPBACK;
1149 flagTest |= IFF_LOOPBACK;
1150
1151 for( p = addrs; p; p = p->ifa_next )
1152 {
1153 if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
1154 {
1155 continue;
1156 }
1157 if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
1158 {
1159 continue;
1160 }
1161 loopback = p;
1162 break;
1163 }
1164
1165 #endif
1166
1167 if( !inMDNS->p->interfaceList && loopback )
1168 {
1169 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
1170 loopback->ifa_name ? loopback->ifa_name : "<null>", loopback->ifa_extra.index, loopback->ifa_addr );
1171
1172 err = SetupInterface( inMDNS, loopback, &ifd );
1173 require_noerr( err, exit );
1174
1175 *next = ifd;
1176 next = &ifd->next;
1177 ++inMDNS->p->interfaceCount;
1178 }
1179
1180 exit:
1181 if( err )
1182 {
1183 TearDownInterfaceList( inMDNS );
1184 }
1185 if( addrs )
1186 {
1187 freeifaddrs( addrs );
1188 }
1189 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
1190 return( err );
1191 }
1192
1193 //===========================================================================================================================
1194 // TearDownInterfaceList
1195 //===========================================================================================================================
1196
1197 mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS )
1198 {
1199 mStatus err;
1200 mDNSInterfaceData * ifd;
1201
1202 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
1203 check( inMDNS );
1204 check( inMDNS->p );
1205
1206 // Tear down interface list change notifications.
1207
1208 err = TearDownNotifications( inMDNS );
1209 check_noerr( err );
1210
1211 // Tear down all the interfaces.
1212
1213 while( inMDNS->p->interfaceList )
1214 {
1215 ifd = inMDNS->p->interfaceList;
1216 inMDNS->p->interfaceList = ifd->next;
1217
1218 TearDownInterface( inMDNS, ifd );
1219 }
1220 inMDNS->p->interfaceCount = 0;
1221
1222 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
1223 return( mStatus_NoError );
1224 }
1225
1226 //===========================================================================================================================
1227 // SetupInterface
1228 //===========================================================================================================================
1229
1230 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
1231 {
1232 mStatus err;
1233 mDNSInterfaceData * ifd;
1234 SocketRef sock;
1235
1236 ifd = NULL;
1237 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
1238 check( inMDNS );
1239 check( inMDNS->p );
1240 check( inIFA );
1241 check( inIFA->ifa_addr );
1242 check( outIFD );
1243
1244 // Allocate memory for the interface and initialize it.
1245
1246 ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
1247 require_action( ifd, exit, err = mStatus_NoMemoryErr );
1248 ifd->sock = kInvalidSocketRef;
1249 ifd->index = inIFA->ifa_extra.index;
1250 ifd->scopeID = inIFA->ifa_extra.index;
1251
1252 check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
1253 strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
1254 ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
1255
1256 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
1257 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
1258 // on a large configured network, which means there's a good chance that most or all the other devices on that
1259 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
1260 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
1261 // devices on a large configured network, so we are willing to make that sacrifice.
1262
1263 ifd->interfaceInfo.McastTxRx = mDNStrue;
1264
1265 #if( MDNS_WINDOWS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1266 if( inIFA->ifa_addr->sa_family != AF_INET )
1267 {
1268 const mDNSInterfaceData * p;
1269
1270 for( p = inMDNS->p->interfaceList; p; p = p->next )
1271 {
1272 if( ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
1273 ( ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 ) && ( p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) ) &&
1274 ( strcmp( p->name, inIFA->ifa_name ) == 0 ) )
1275 {
1276 ifd->interfaceInfo.McastTxRx = mDNSfalse;
1277 break;
1278 }
1279 }
1280 }
1281 #endif
1282
1283 // If this is an IPv6 interface, search for its IPv4 equivalent and use that InterfaceID. This causes the IPv4
1284 // interface to send both A and AAAA records so we can publish IPv6 support without doubling the packet rate.
1285 // Note: this search only works because we register all IPv4 interfaces before IPv6 interfaces.
1286
1287 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
1288
1289 #if( MDNS_WINDOWS_AAAA_OVER_IPV4 )
1290 if( inIFA->ifa_addr->sa_family != AF_INET )
1291 {
1292 mDNSInterfaceData * ipv4IFD;
1293
1294 for( ipv4IFD = inMDNS->p->interfaceList; ipv4IFD; ipv4IFD = ipv4IFD->next )
1295 {
1296 if( strcmp( ipv4IFD->name, ifd->name ) == 0 )
1297 {
1298 ipv4IFD->scopeID = ifd->scopeID;
1299 ifd->interfaceInfo.McastTxRx = mDNSfalse;
1300 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ipv4IFD;
1301 break;
1302 }
1303 }
1304 }
1305 #endif
1306
1307 // Set up a socket for this interface (if needed).
1308
1309 if( ifd->interfaceInfo.McastTxRx )
1310 {
1311 err = SetupSocket( inMDNS, inIFA->ifa_addr, &sock );
1312 require_noerr( err, exit );
1313 ifd->sock = sock;
1314 ifd->defaultAddr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
1315
1316 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
1317
1318 #if( !TARGET_OS_WINDOWS_CE )
1319 {
1320 DWORD size;
1321
1322 err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
1323 &ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL );
1324 if( err != 0 )
1325 {
1326 ifd->wsaRecvMsgFunctionPtr = NULL;
1327 }
1328 }
1329 #endif
1330
1331 // Set up the read pending event and associate it so we can block until data is available for this socket.
1332
1333 ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1334 err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
1335 require_noerr( err, exit );
1336
1337 err = WSAEventSelect( ifd->sock, ifd->readPendingEvent, FD_READ );
1338 require_noerr( err, exit );
1339 }
1340 else
1341 {
1342 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
1343
1344 ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1345 err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
1346 require_noerr( err, exit );
1347 }
1348
1349 // Register this interface with mDNS.
1350
1351 err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
1352 require_noerr( err, exit );
1353
1354 ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
1355
1356 err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo );
1357 require_noerr( err, exit );
1358 ifd->hostRegistered = mDNStrue;
1359
1360 dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
1361
1362 // Success!
1363
1364 *outIFD = ifd;
1365 ifd = NULL;
1366
1367 exit:
1368 if( ifd )
1369 {
1370 TearDownInterface( inMDNS, ifd );
1371 }
1372 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
1373 return( err );
1374 }
1375
1376 //===========================================================================================================================
1377 // TearDownInterface
1378 //===========================================================================================================================
1379
1380 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
1381 {
1382 SocketRef sock;
1383
1384 check( inMDNS );
1385 check( inIFD );
1386
1387 // Deregister this interface with mDNS.
1388
1389 dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
1390
1391 if( inIFD->hostRegistered )
1392 {
1393 inIFD->hostRegistered = mDNSfalse;
1394 mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo );
1395 }
1396
1397 // Tear down the multicast socket.
1398
1399 if( inIFD->readPendingEvent )
1400 {
1401 CloseHandle( inIFD->readPendingEvent );
1402 inIFD->readPendingEvent = 0;
1403 }
1404
1405 sock = inIFD->sock;
1406 inIFD->sock = kInvalidSocketRef;
1407 if( IsValidSocket( sock ) )
1408 {
1409 close_compat( sock );
1410 }
1411
1412 // Free the memory used by the interface info.
1413
1414 free( inIFD );
1415 return( mStatus_NoError );
1416 }
1417
1418 //===========================================================================================================================
1419 // SetupSocket
1420 //===========================================================================================================================
1421
1422 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, SocketRef *outSocketRef )
1423 {
1424 mStatus err;
1425 SocketRef sock;
1426 int option;
1427
1428 DEBUG_UNUSED( inMDNS );
1429
1430 dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
1431 check( inMDNS );
1432 check( outSocketRef );
1433
1434 // Set up an IPv4 or IPv6 UDP socket.
1435
1436 sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
1437 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
1438 require_noerr( err, exit );
1439
1440 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets.
1441
1442 option = 1;
1443 err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
1444 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1445
1446 if( inAddr->sa_family == AF_INET )
1447 {
1448 mDNSv4Addr ipv4;
1449 struct sockaddr_in sa4;
1450 struct ip_mreq mreqv4;
1451
1452 // Bind to the multicast DNS port 5353.
1453
1454 ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
1455 memset( &sa4, 0, sizeof( sa4 ) );
1456 sa4.sin_family = AF_INET;
1457 sa4.sin_port = MulticastDNSPort.NotAnInteger;
1458 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
1459
1460 err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
1461 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
1462
1463 // Turn on option to receive destination addresses and receiving interface.
1464
1465 option = 1;
1466 err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
1467 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1468
1469 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1470
1471 mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
1472 mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
1473 err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
1474 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1475
1476 // Specify the interface to send multicast packets on this socket.
1477
1478 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
1479 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
1480 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1481
1482 // Send unicast packets with TTL 255 (helps against spoofing).
1483
1484 option = 255;
1485 err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
1486 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1487
1488 // Send multicast packets with TTL 255 (helps against spoofing).
1489
1490 option = 255;
1491 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
1492 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1493
1494 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
1495
1496 option = 1;
1497 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
1498 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1499 }
1500 else if( inAddr->sa_family == AF_INET6 )
1501 {
1502 struct sockaddr_in6 * sa6p;
1503 struct sockaddr_in6 sa6;
1504 struct ipv6_mreq mreqv6;
1505
1506 sa6p = (struct sockaddr_in6 *) inAddr;
1507
1508 // Bind to the multicast DNS port 5353.
1509
1510 memset( &sa6, 0, sizeof( sa6 ) );
1511 sa6.sin6_family = AF_INET6;
1512 sa6.sin6_port = MulticastDNSPort.NotAnInteger;
1513 sa6.sin6_flowinfo = 0;
1514 sa6.sin6_addr = sa6p->sin6_addr;
1515 sa6.sin6_scope_id = sa6p->sin6_scope_id;
1516
1517 err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
1518 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
1519
1520 // Turn on option to receive destination addresses and receiving interface.
1521
1522 option = 1;
1523 err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
1524 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1525
1526 // Turn on option to receive TTL so we can check for spoofing.
1527
1528 option = 1;
1529 err = setsockopt( sock, IPPROTO_IPV6, IPV6_HOPLIMIT, (char *) &option, sizeof( option ) );
1530 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1531
1532 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
1533 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
1534 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
1535
1536 #if( defined( IPV6_V6ONLY ) )
1537 option = 1;
1538 err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
1539 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1540 #endif
1541
1542 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1543
1544 mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
1545 mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
1546 err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
1547 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1548
1549 // Specify the interface to send multicast packets on this socket.
1550
1551 option = (int) sa6p->sin6_scope_id;
1552 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
1553 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1554
1555 // Send unicast packets with TTL 255 (helps against spoofing).
1556
1557 option = 255;
1558 err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
1559 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1560
1561 // Send multicast packets with TTL 255 (helps against spoofing).
1562
1563 option = 255;
1564 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
1565 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1566
1567 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
1568
1569 option = 1;
1570 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
1571 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1572 }
1573 else
1574 {
1575 dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
1576 err = kUnsupportedErr;
1577 goto exit;
1578 }
1579
1580 // Success!
1581
1582 *outSocketRef = sock;
1583 sock = kInvalidSocketRef;
1584 err = mStatus_NoError;
1585
1586 exit:
1587 if( IsValidSocket( sock ) )
1588 {
1589 close_compat( sock );
1590 }
1591 return( err );
1592 }
1593
1594 //===========================================================================================================================
1595 // SetupSocket
1596 //===========================================================================================================================
1597
1598 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
1599 {
1600 mStatus err;
1601
1602 check( inSA );
1603 check( outIP );
1604
1605 if( inSA->sa_family == AF_INET )
1606 {
1607 struct sockaddr_in * sa4;
1608
1609 sa4 = (struct sockaddr_in *) inSA;
1610 outIP->type = mDNSAddrType_IPv4;
1611 outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
1612 if( outPort )
1613 {
1614 outPort->NotAnInteger = sa4->sin_port;
1615 }
1616 err = mStatus_NoError;
1617 }
1618 else if( inSA->sa_family == AF_INET6 )
1619 {
1620 struct sockaddr_in6 * sa6;
1621
1622 sa6 = (struct sockaddr_in6 *) inSA;
1623 outIP->type = mDNSAddrType_IPv6;
1624 outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
1625 if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
1626 {
1627 outIP->ip.v6.w[ 1 ] = 0;
1628 }
1629 if( outPort )
1630 {
1631 outPort->NotAnInteger = sa6->sin6_port;
1632 }
1633 err = mStatus_NoError;
1634 }
1635 else
1636 {
1637 dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
1638 err = mStatus_BadParamErr;
1639 }
1640 return( err );
1641 }
1642
1643 //===========================================================================================================================
1644 // SetupNotifications
1645 //===========================================================================================================================
1646
1647 mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS )
1648 {
1649 mStatus err;
1650 SocketRef sock;
1651 unsigned long param;
1652 int inBuffer;
1653 int outBuffer;
1654 DWORD outSize;
1655
1656 // Register to listen for address list changes.
1657
1658 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1659 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
1660 require_noerr( err, exit );
1661 inMDNS->p->interfaceListChangedSocket = sock;
1662
1663 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1664 // when a change to the interface list is detected.
1665
1666 param = 1;
1667 err = ioctlsocket( sock, FIONBIO, &param );
1668 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1669 require_noerr( err, exit );
1670
1671 inBuffer = 0;
1672 outBuffer = 0;
1673 err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1674 if( err < 0 )
1675 {
1676 check( errno_compat() == WSAEWOULDBLOCK );
1677 }
1678
1679 err = WSAEventSelect( sock, inMDNS->p->interfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
1680 err = translate_errno( err == 0, errno_compat(), kUnknownErr );
1681 require_noerr( err, exit );
1682
1683 exit:
1684 if( err )
1685 {
1686 TearDownNotifications( inMDNS );
1687 }
1688 return( err );
1689 }
1690
1691 //===========================================================================================================================
1692 // TearDownNotifications
1693 //===========================================================================================================================
1694
1695 mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS )
1696 {
1697 if( IsValidSocket( inMDNS->p->interfaceListChangedSocket ) )
1698 {
1699 close_compat( inMDNS->p->interfaceListChangedSocket );
1700 inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
1701 }
1702 return( mStatus_NoError );
1703 }
1704
1705 #if 0
1706 #pragma mark -
1707 #endif
1708
1709 //===========================================================================================================================
1710 // SetupThread
1711 //===========================================================================================================================
1712
1713 mDNSlocal mStatus SetupThread( mDNS * const inMDNS )
1714 {
1715 mStatus err;
1716 HANDLE threadHandle;
1717 unsigned threadID;
1718 DWORD result;
1719
1720 dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread\n" );
1721
1722 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
1723 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
1724
1725 inMDNS->p->initEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1726 err = translate_errno( inMDNS->p->initEvent, (mStatus) GetLastError(), kUnknownErr );
1727 require_noerr( err, exit );
1728
1729 inMDNS->p->initStatus = mStatus_Invalid;
1730
1731 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1732 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1733
1734 threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, ProcessingThread, inMDNS, 0, &threadID );
1735 err = translate_errno( threadHandle, (mStatus) GetLastError(), kUnknownErr );
1736 require_noerr( err, exit );
1737
1738 result = WaitForSingleObject( inMDNS->p->initEvent, INFINITE );
1739 err = translate_errno( result == WAIT_OBJECT_0, (mStatus) GetLastError(), kUnknownErr );
1740 require_noerr( err, exit );
1741 err = inMDNS->p->initStatus;
1742 require_noerr( err, exit );
1743
1744 exit:
1745 if( inMDNS->p->initEvent )
1746 {
1747 CloseHandle( inMDNS->p->initEvent );
1748 inMDNS->p->initEvent = 0;
1749 }
1750 dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread done (err=%d %m)\n", err, err );
1751 return( err );
1752 }
1753
1754 //===========================================================================================================================
1755 // TearDownThread
1756 //===========================================================================================================================
1757
1758 mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS )
1759 {
1760 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
1761 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
1762
1763 if( inMDNS->p->cancelEvent )
1764 {
1765 BOOL wasSet;
1766 DWORD result;
1767
1768 wasSet = SetEvent( inMDNS->p->cancelEvent );
1769 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
1770
1771 if( inMDNS->p->quitEvent )
1772 {
1773 result = WaitForSingleObject( inMDNS->p->quitEvent, 5 * 1000 );
1774 check_translated_errno( result == WAIT_OBJECT_0, GetLastError(), kUnknownErr );
1775 }
1776 }
1777 return( mStatus_NoError );
1778 }
1779
1780 //===========================================================================================================================
1781 // ProcessingThread
1782 //===========================================================================================================================
1783
1784 mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
1785 {
1786 mDNS * m;
1787 int done;
1788 mStatus err;
1789 HANDLE * waitList;
1790 int waitListCount;
1791 DWORD result;
1792 BOOL wasSet;
1793
1794 check( inParam );
1795
1796 m = (mDNS *) inParam;
1797 err = ProcessingThreadInitialize( m );
1798 require_noerr( err, exit );
1799
1800 done = 0;
1801 while( !done )
1802 {
1803 // Set up the list of objects we'll be waiting on.
1804
1805 waitList = NULL;
1806 waitListCount = 0;
1807 err = ProcessingThreadSetupWaitList( m, &waitList, &waitListCount );
1808 require_noerr( err, exit );
1809
1810 // Main processing loop.
1811
1812 for( ;; )
1813 {
1814 // Give the mDNS core a chance to do its work and determine next event time.
1815
1816 mDNSs32 interval = mDNS_Execute(m) - mDNSPlatformTimeNow();
1817 if (interval < 0) interval = 0;
1818 else if (interval > (0x7FFFFFFF / 1000)) interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
1819 else interval = (interval * 1000) / mDNSPlatformOneSecond;
1820
1821 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1822
1823 result = WaitForMultipleObjects( (DWORD) waitListCount, waitList, FALSE, (DWORD) interval );
1824 if( result == WAIT_TIMEOUT )
1825 {
1826 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1827
1828 dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
1829 continue;
1830 }
1831 else if( result == kWaitListCancelEvent )
1832 {
1833 // Cancel event. Set the done flag and break to exit.
1834
1835 dlog( kDebugLevelVerbose, DEBUG_NAME "canceling...\n" );
1836 done = 1;
1837 break;
1838 }
1839 else if( result == kWaitListInterfaceListChangedEvent )
1840 {
1841 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1842
1843 ProcessingThreadInterfaceListChanged( m );
1844 break;
1845 }
1846 else if( result == kWaitListWakeupEvent )
1847 {
1848 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
1849
1850 dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup for mDNS_Execute\n" );
1851 continue;
1852 }
1853 else
1854 {
1855 int waitItemIndex;
1856
1857 // Socket data available event. Determine which socket and process the packet.
1858
1859 waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
1860 dlog( kDebugLevelChatty, DEBUG_NAME "socket data available on socket index %d\n", waitItemIndex );
1861 check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
1862 if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
1863 {
1864 HANDLE signaledObject;
1865 int n;
1866 mDNSInterfaceData * ifd;
1867
1868 signaledObject = waitList[ waitItemIndex ];
1869
1870 n = 0;
1871 for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
1872 {
1873 if( ifd->readPendingEvent == signaledObject )
1874 {
1875 ProcessingThreadProcessPacket( m, ifd, ifd->sock );
1876 ++n;
1877 }
1878 }
1879 check( n > 0 );
1880 }
1881 else
1882 {
1883 // Unexpected wait result.
1884
1885 dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
1886 }
1887 }
1888 }
1889
1890 // Release the wait list.
1891
1892 if( waitList )
1893 {
1894 free( waitList );
1895 waitList = NULL;
1896 waitListCount = 0;
1897 }
1898 }
1899
1900 // Signal the quit event to indicate that the thread is finished.
1901
1902 exit:
1903 wasSet = SetEvent( m->p->quitEvent );
1904 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
1905
1906 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
1907 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1908
1909 _endthreadex_compat( 0 );
1910 return( 0 );
1911 }
1912
1913 //===========================================================================================================================
1914 // ProcessingThreadInitialize
1915 //===========================================================================================================================
1916
1917 mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
1918 {
1919 mStatus err;
1920 BOOL wasSet;
1921
1922 inMDNS->p->threadID = GetCurrentThreadId();
1923
1924 err = SetupInterfaceList( inMDNS );
1925 require_noerr( err, exit );
1926
1927 exit:
1928 if( err )
1929 {
1930 TearDownInterfaceList( inMDNS );
1931 }
1932 inMDNS->p->initStatus = err;
1933
1934 wasSet = SetEvent( inMDNS->p->initEvent );
1935 check_translated_errno( wasSet, GetLastError(), kUnknownErr );
1936 return( err );
1937 }
1938
1939 //===========================================================================================================================
1940 // ProcessingThreadSetupWaitList
1941 //===========================================================================================================================
1942
1943 mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
1944 {
1945 mStatus err;
1946 int waitListCount;
1947 HANDLE * waitList;
1948 HANDLE * waitItemPtr;
1949 mDNSInterfaceData * ifd;
1950
1951 dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
1952 check( inMDNS );
1953 check( inMDNS->p );
1954 check( outWaitList );
1955 check( outWaitListCount );
1956
1957 // Allocate an array to hold all the objects to wait on.
1958
1959 waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount;
1960 waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
1961 require_action( waitList, exit, err = mStatus_NoMemoryErr );
1962 waitItemPtr = waitList;
1963
1964 // Add the fixed wait items to the beginning of the list.
1965
1966 *waitItemPtr++ = inMDNS->p->cancelEvent;
1967 *waitItemPtr++ = inMDNS->p->interfaceListChangedEvent;
1968 *waitItemPtr++ = inMDNS->p->wakeupEvent;
1969
1970 // Append all the dynamic wait items to the list.
1971
1972 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
1973 {
1974 *waitItemPtr++ = ifd->readPendingEvent;
1975 }
1976 check( (int)( waitItemPtr - waitList ) == waitListCount );
1977
1978 *outWaitList = waitList;
1979 *outWaitListCount = waitListCount;
1980 waitList = NULL;
1981 err = mStatus_NoError;
1982
1983 exit:
1984 if( waitList )
1985 {
1986 free( waitList );
1987 }
1988 dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list done (err=%d %m)\n", err, err );
1989 return( err );
1990 }
1991
1992 //===========================================================================================================================
1993 // ProcessingThreadProcessPacket
1994 //===========================================================================================================================
1995
1996 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock )
1997 {
1998 OSStatus err;
1999 mDNSAddr srcAddr;
2000 mDNSIPPort srcPort;
2001 mDNSAddr dstAddr;
2002 mDNSIPPort dstPort;
2003 mDNSu8 ttl;
2004 struct sockaddr_storage addr;
2005 DNSMessage packet;
2006 mDNSu8 * end;
2007 int n;
2008
2009 check( inMDNS );
2010 check( inIFD );
2011 check( IsValidSocket( inSock ) );
2012
2013 // Set up the default in case the packet info options are not supported or reported correctly.
2014
2015 dstAddr = inIFD->defaultAddr;
2016 dstPort = MulticastDNSPort;
2017 ttl = 255;
2018
2019 #if( !TARGET_OS_WINDOWS_CE )
2020 if( inIFD->wsaRecvMsgFunctionPtr )
2021 {
2022 WSAMSG msg;
2023 WSABUF buf;
2024 uint8_t controlBuffer[ 128 ];
2025 DWORD size;
2026 LPWSACMSGHDR header;
2027
2028 // Set up the buffer and read the packet.
2029
2030 msg.name = (LPSOCKADDR) &addr;
2031 msg.namelen = (INT) sizeof( addr );
2032 buf.buf = (char *) &packet;
2033 buf.len = (u_long) sizeof( packet );
2034 msg.lpBuffers = &buf;
2035 msg.dwBufferCount = 1;
2036 msg.Control.buf = (char *) controlBuffer;
2037 msg.Control.len = (u_long) sizeof( controlBuffer );
2038 msg.dwFlags = 0;
2039
2040 err = inIFD->wsaRecvMsgFunctionPtr( inSock, &msg, &size, NULL, NULL );
2041 err = translate_errno( err == 0, (OSStatus) GetLastError(), kUnknownErr );
2042 require_noerr( err, exit );
2043 n = (int) size;
2044
2045 // Parse the control information. Reject packets received on the wrong interface.
2046
2047 for( header = WSA_CMSG_FIRSTHDR( &msg ); header; header = WSA_CMSG_NXTHDR( &msg, header ) )
2048 {
2049 if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
2050 {
2051 IN_PKTINFO * ipv4PacketInfo;
2052
2053 ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
2054 require_action( ipv4PacketInfo->ipi_ifindex == ( inIFD->index >> 8 ), exit, err = kMismatchErr );
2055
2056 dstAddr.type = mDNSAddrType_IPv4;
2057 dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
2058 }
2059 else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
2060 {
2061 IN6_PKTINFO * ipv6PacketInfo;
2062
2063 ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
2064 require_action( ipv6PacketInfo->ipi6_ifindex == inIFD->index, exit, err = kMismatchErr );
2065
2066 dstAddr.type = mDNSAddrType_IPv6;
2067 dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
2068 }
2069 else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_HOPLIMIT ) )
2070 {
2071 ttl = (mDNSu8) *( (int *) WSA_CMSG_DATA( header ) );
2072 }
2073 }
2074 }
2075 else
2076 #endif
2077 {
2078 int addrSize;
2079
2080 addrSize = sizeof( addr );
2081 n = recvfrom( inSock, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
2082 err = translate_errno( n > 0, errno_compat(), kUnknownErr );
2083 require_noerr( err, exit );
2084 }
2085 SockAddrToMDNSAddr( (struct sockaddr *) &addr, &srcAddr, &srcPort );
2086
2087 // Dispatch the packet to mDNS.
2088
2089 dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
2090 dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", n );
2091 dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
2092 dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
2093 dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
2094 dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
2095
2096 end = ( (mDNSu8 *) &packet ) + n;
2097 mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->interfaceInfo.InterfaceID, ttl );
2098
2099 exit:
2100 return;
2101 }
2102
2103 //===========================================================================================================================
2104 // ProcessingThreadInterfaceListChanged
2105 //===========================================================================================================================
2106
2107 mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
2108 {
2109 mStatus err;
2110
2111 dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
2112 check( inMDNS );
2113
2114 mDNSPlatformLock( inMDNS );
2115
2116 // Tear down the existing interfaces and set up new ones using the new IP info.
2117
2118 err = TearDownInterfaceList( inMDNS );
2119 check_noerr( err );
2120
2121 err = SetupInterfaceList( inMDNS );
2122 check_noerr( err );
2123
2124 mDNSPlatformUnlock( inMDNS );
2125
2126 // Inform clients of the change.
2127
2128 if( inMDNS->MainCallback )
2129 {
2130 inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged );
2131 }
2132
2133 // Force mDNS to update.
2134
2135 mDNSCoreMachineSleep( inMDNS, mDNSfalse );
2136 }
2137
2138 #if 0
2139 #pragma mark -
2140 #pragma mark == Utilities ==
2141 #endif
2142
2143 //===========================================================================================================================
2144 // getifaddrs
2145 //===========================================================================================================================
2146
2147 int getifaddrs( struct ifaddrs **outAddrs )
2148 {
2149 int err;
2150
2151 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
2152
2153 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
2154 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
2155
2156 if( !gIPHelperLibraryInstance )
2157 {
2158 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
2159 if( gIPHelperLibraryInstance )
2160 {
2161 gGetAdaptersAddressesFunctionPtr =
2162 (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
2163 if( !gGetAdaptersAddressesFunctionPtr )
2164 {
2165 BOOL ok;
2166
2167 ok = FreeLibrary( gIPHelperLibraryInstance );
2168 check_translated_errno( ok, GetLastError(), kUnknownErr );
2169 gIPHelperLibraryInstance = NULL;
2170 }
2171 }
2172 }
2173
2174 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
2175
2176 if( gGetAdaptersAddressesFunctionPtr )
2177 {
2178 err = getifaddrs_ipv6( outAddrs );
2179 require_noerr( err, exit );
2180 }
2181 else
2182 {
2183 err = getifaddrs_ipv4( outAddrs );
2184 require_noerr( err, exit );
2185 }
2186
2187 #elif( !TARGET_OS_WINDOWS_CE )
2188
2189 err = getifaddrs_ipv4( outAddrs );
2190 require_noerr( err, exit );
2191
2192 #else
2193
2194 err = getifaddrs_ce( outAddrs );
2195 require_noerr( err, exit );
2196
2197 #endif
2198
2199 exit:
2200 return( err );
2201 }
2202
2203 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
2204 //===========================================================================================================================
2205 // getifaddrs_ipv6
2206 //===========================================================================================================================
2207
2208 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
2209 {
2210 DWORD err;
2211 int i;
2212 DWORD flags;
2213 struct ifaddrs * head;
2214 struct ifaddrs ** next;
2215 IP_ADAPTER_ADDRESSES * iaaList;
2216 ULONG iaaListSize;
2217 IP_ADAPTER_ADDRESSES * iaa;
2218 size_t size;
2219 struct ifaddrs * ifa;
2220
2221 check( gGetAdaptersAddressesFunctionPtr );
2222
2223 head = NULL;
2224 next = &head;
2225 iaaList = NULL;
2226
2227 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
2228 // This loops to handle the case where the interface changes in the window after getting the size, but before the
2229 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
2230
2231 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
2232 i = 0;
2233 for( ;; )
2234 {
2235 iaaListSize = 0;
2236 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
2237 check( err == ERROR_BUFFER_OVERFLOW );
2238 check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
2239
2240 iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
2241 require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
2242
2243 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
2244 if( err == ERROR_SUCCESS ) break;
2245
2246 free( iaaList );
2247 iaaList = NULL;
2248 ++i;
2249 require( i < 100, exit );
2250 dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
2251 }
2252
2253 for( iaa = iaaList; iaa; iaa = iaa->Next )
2254 {
2255 IP_ADAPTER_UNICAST_ADDRESS * addr;
2256
2257 if( iaa->IfIndex > 0xFFFFFF )
2258 {
2259 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
2260 }
2261 if( iaa->Ipv6IfIndex > 0xFF )
2262 {
2263 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
2264 }
2265
2266 // Skip psuedo and tunnel interfaces.
2267
2268 if( ( iaa->Ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
2269 {
2270 continue;
2271 }
2272
2273 // Add each address as a separate interface to emulate the way getifaddrs works.
2274
2275 for( addr = iaa->FirstUnicastAddress; addr; addr = addr->Next )
2276 {
2277 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
2278 require_action( ifa, exit, err = WSAENOBUFS );
2279
2280 *next = ifa;
2281 next = &ifa->ifa_next;
2282
2283 // Get the name.
2284
2285 size = strlen( iaa->AdapterName ) + 1;
2286 ifa->ifa_name = (char *) malloc( size );
2287 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
2288 memcpy( ifa->ifa_name, iaa->AdapterName, size );
2289
2290 // Get interface flags.
2291
2292 ifa->ifa_flags = 0;
2293 if( iaa->OperStatus == IfOperStatusUp )
2294 {
2295 ifa->ifa_flags |= IFF_UP;
2296 }
2297 if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK )
2298 {
2299 ifa->ifa_flags |= IFF_LOOPBACK;
2300 }
2301 if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) )
2302 {
2303 ifa->ifa_flags |= IFF_MULTICAST;
2304 }
2305
2306 // Get the interface index. Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes
2307 // so the following is a hack to put IPv4 interface indexes in the upper 16-bits and IPv6 interface indexes
2308 // in the lower 16-bits. This allows the IPv6 interface index to be usable as an IPv6 scope ID directly.
2309
2310 switch( addr->Address.lpSockaddr->sa_family )
2311 {
2312 case AF_INET:
2313 ifa->ifa_extra.index = iaa->IfIndex << 8;
2314 break;
2315
2316 case AF_INET6:
2317 ifa->ifa_extra.index = iaa->Ipv6IfIndex;
2318 break;
2319
2320 default:
2321 break;
2322 }
2323
2324 // Get addresses.
2325
2326 switch( addr->Address.lpSockaddr->sa_family )
2327 {
2328 case AF_INET:
2329 case AF_INET6:
2330 ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
2331 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
2332 memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
2333 break;
2334
2335 default:
2336 break;
2337 }
2338 }
2339 }
2340
2341 // Success!
2342
2343 if( outAddrs )
2344 {
2345 *outAddrs = head;
2346 head = NULL;
2347 }
2348 err = ERROR_SUCCESS;
2349
2350 exit:
2351 if( head )
2352 {
2353 freeifaddrs( head );
2354 }
2355 if( iaaList )
2356 {
2357 free( iaaList );
2358 }
2359 return( (int) err );
2360 }
2361 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
2362
2363 #if( !TARGET_OS_WINDOWS_CE )
2364 //===========================================================================================================================
2365 // getifaddrs_ipv4
2366 //===========================================================================================================================
2367
2368 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
2369 {
2370 int err;
2371 SOCKET sock;
2372 DWORD size;
2373 DWORD actualSize;
2374 INTERFACE_INFO * buffer;
2375 INTERFACE_INFO * tempBuffer;
2376 INTERFACE_INFO * ifInfo;
2377 int n;
2378 int i;
2379 struct ifaddrs * head;
2380 struct ifaddrs ** next;
2381 struct ifaddrs * ifa;
2382
2383 sock = INVALID_SOCKET;
2384 buffer = NULL;
2385 head = NULL;
2386 next = &head;
2387
2388 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
2389 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
2390 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
2391
2392 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
2393 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2394 require_noerr( err, exit );
2395
2396 n = 0;
2397 size = 16 * sizeof( INTERFACE_INFO );
2398 for( ;; )
2399 {
2400 tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
2401 require_action( tempBuffer, exit, err = WSAENOBUFS );
2402 buffer = tempBuffer;
2403
2404 err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
2405 if( err == 0 )
2406 {
2407 break;
2408 }
2409
2410 ++n;
2411 require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
2412
2413 size += ( 16 * sizeof( INTERFACE_INFO ) );
2414 }
2415 check( actualSize <= size );
2416 check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
2417 n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
2418
2419 // Process the raw interface list and build a linked list of IPv4 interfaces.
2420
2421 for( i = 0; i < n; ++i )
2422 {
2423 ifInfo = &buffer[ i ];
2424 if( ifInfo->iiAddress.Address.sa_family != AF_INET )
2425 {
2426 continue;
2427 }
2428
2429 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
2430 require_action( ifa, exit, err = WSAENOBUFS );
2431
2432 *next = ifa;
2433 next = &ifa->ifa_next;
2434
2435 // Get the name.
2436
2437 ifa->ifa_name = (char *) malloc( 16 );
2438 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
2439 sprintf( ifa->ifa_name, "%d", i + 1 );
2440
2441 // Get interface flags.
2442
2443 ifa->ifa_flags = (u_int) ifInfo->iiFlags;
2444
2445 // Get addresses.
2446
2447 switch( ifInfo->iiAddress.Address.sa_family )
2448 {
2449 case AF_INET:
2450 {
2451 struct sockaddr_in * sa4;
2452
2453 sa4 = &ifInfo->iiAddress.AddressIn;
2454 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
2455 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
2456 memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
2457 break;
2458 }
2459
2460 default:
2461 break;
2462 }
2463
2464 // Emulate an interface index.
2465
2466 ifa->ifa_extra.index = (uint32_t)( i + 1 );
2467 }
2468
2469 // Success!
2470
2471 if( outAddrs )
2472 {
2473 *outAddrs = head;
2474 head = NULL;
2475 }
2476 err = 0;
2477
2478 exit:
2479 if( head )
2480 {
2481 freeifaddrs( head );
2482 }
2483 if( buffer )
2484 {
2485 free( buffer );
2486 }
2487 if( sock != INVALID_SOCKET )
2488 {
2489 closesocket( sock );
2490 }
2491 return( err );
2492 }
2493 #endif // !TARGET_OS_WINDOWS_CE )
2494
2495 #if( TARGET_OS_WINDOWS_CE )
2496 //===========================================================================================================================
2497 // getifaddrs_ce
2498 //===========================================================================================================================
2499
2500 mDNSlocal int getifaddrs_ce( struct ifaddrs **outAddrs )
2501 {
2502 int err;
2503 SocketRef sock;
2504 DWORD size;
2505 void * buffer;
2506 SOCKET_ADDRESS_LIST * addressList;
2507 struct ifaddrs * head;
2508 struct ifaddrs ** next;
2509 struct ifaddrs * ifa;
2510 int n;
2511 int i;
2512
2513 sock = kInvalidSocketRef;
2514 buffer = NULL;
2515 head = NULL;
2516 next = &head;
2517
2518 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
2519
2520 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
2521 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2522 require_noerr( err, exit );
2523
2524 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
2525 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
2526 //
2527 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
2528
2529 size = 0;
2530 WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL );
2531 require_action( size > 0, exit, err = -1 );
2532 size *= 2;
2533
2534 buffer = calloc( 1, size );
2535 require_action( buffer, exit, err = -1 );
2536
2537 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
2538
2539 err = WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, size, &size, NULL, NULL );
2540 require_noerr( err, exit );
2541 addressList = (SOCKET_ADDRESS_LIST *) buffer;
2542
2543 // Process the raw interface list and build a linked list of interfaces.
2544 //
2545 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
2546
2547 n = addressList->iAddressCount;
2548 if( n == 0 )
2549 {
2550 n = 1;
2551 }
2552 for( i = 0; i < n; ++i )
2553 {
2554 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
2555 require_action( ifa, exit, err = WSAENOBUFS );
2556
2557 *next = ifa;
2558 next = &ifa->ifa_next;
2559
2560 // Get the name.
2561
2562 ifa->ifa_name = (char *) malloc( 16 );
2563 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
2564 sprintf( ifa->ifa_name, "%d", i + 1 );
2565
2566 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
2567
2568 ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
2569
2570 // Get addresses.
2571
2572 switch( addressList->Address[ i ].lpSockaddr->sa_family )
2573 {
2574 case AF_INET:
2575 {
2576 struct sockaddr_in * sa4;
2577
2578 sa4 = (struct sockaddr_in *) addressList->Address[ i ].lpSockaddr;
2579 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
2580 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
2581 memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
2582 break;
2583 }
2584
2585 default:
2586 break;
2587 }
2588 }
2589
2590 // Success!
2591
2592 if( outAddrs )
2593 {
2594 *outAddrs = head;
2595 head = NULL;
2596 }
2597 err = 0;
2598
2599 exit:
2600 if( head )
2601 {
2602 freeifaddrs( head );
2603 }
2604 if( buffer )
2605 {
2606 free( buffer );
2607 }
2608 if( sock != INVALID_SOCKET )
2609 {
2610 closesocket( sock );
2611 }
2612 return( err );
2613 }
2614 #endif // TARGET_OS_WINDOWS_CE )
2615
2616 //===========================================================================================================================
2617 // freeifaddrs
2618 //===========================================================================================================================
2619
2620 void freeifaddrs( struct ifaddrs *inIFAs )
2621 {
2622 struct ifaddrs * p;
2623 struct ifaddrs * q;
2624
2625 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
2626
2627 for( p = inIFAs; p; p = q )
2628 {
2629 q = p->ifa_next;
2630
2631 if( p->ifa_name )
2632 {
2633 free( p->ifa_name );
2634 p->ifa_name = NULL;
2635 }
2636 if( p->ifa_addr )
2637 {
2638 free( p->ifa_addr );
2639 p->ifa_addr = NULL;
2640 }
2641 if( p->ifa_netmask )
2642 {
2643 free( p->ifa_netmask );
2644 p->ifa_netmask = NULL;
2645 }
2646 if( p->ifa_broadaddr )
2647 {
2648 free( p->ifa_broadaddr );
2649 p->ifa_broadaddr = NULL;
2650 }
2651 if( p->ifa_dstaddr )
2652 {
2653 free( p->ifa_dstaddr );
2654 p->ifa_dstaddr = NULL;
2655 }
2656 if( p->ifa_data )
2657 {
2658 free( p->ifa_data );
2659 p->ifa_data = NULL;
2660 }
2661 free( p );
2662 }
2663 }
2664
2665 //===========================================================================================================================
2666 // CanReceiveUnicast
2667 //===========================================================================================================================
2668
2669 mDNSlocal mDNSBool CanReceiveUnicast( void )
2670 {
2671 mDNSBool ok;
2672 SocketRef sock;
2673 struct sockaddr_in addr;
2674
2675 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
2676
2677 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
2678 check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2679 ok = IsValidSocket( sock );
2680 if( ok )
2681 {
2682 memset( &addr, 0, sizeof( addr ) );
2683 addr.sin_family = AF_INET;
2684 addr.sin_port = MulticastDNSPort.NotAnInteger;
2685 addr.sin_addr.s_addr = htonl( INADDR_ANY );
2686
2687 ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
2688 close_compat( sock );
2689 }
2690
2691 dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
2692 return( ok );
2693 }
2694
2695 //===========================================================================================================================
2696 // GetWindowsVersionString
2697 //===========================================================================================================================
2698
2699 mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
2700 {
2701 #if( !defined( VER_PLATFORM_WIN32_CE ) )
2702 #define VER_PLATFORM_WIN32_CE 3
2703 #endif
2704
2705 OSStatus err;
2706 OSVERSIONINFO osInfo;
2707 BOOL ok;
2708 const char * versionString;
2709 DWORD platformID;
2710 DWORD majorVersion;
2711 DWORD minorVersion;
2712 DWORD buildNumber;
2713
2714 versionString = "unknown Windows version";
2715
2716 osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
2717 ok = GetVersionEx( &osInfo );
2718 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
2719 require_noerr( err, exit );
2720
2721 platformID = osInfo.dwPlatformId;
2722 majorVersion = osInfo.dwMajorVersion;
2723 minorVersion = osInfo.dwMinorVersion;
2724 buildNumber = osInfo.dwBuildNumber & 0xFFFF;
2725
2726 if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
2727 {
2728 if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
2729 {
2730 versionString = "Windows 95";
2731 }
2732 else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
2733 {
2734 versionString = "Windows 95 SP1";
2735 }
2736 else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
2737 {
2738 versionString = "Windows 95 OSR2";
2739 }
2740 else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
2741 {
2742 versionString = "Windows 98";
2743 }
2744 else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
2745 {
2746 versionString = "Windows 98 SP1";
2747 }
2748 else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
2749 {
2750 versionString = "Windows 98 SE";
2751 }
2752 else if( minorVersion == 90 )
2753 {
2754 versionString = "Windows ME";
2755 }
2756 }
2757 else if( platformID == VER_PLATFORM_WIN32_NT )
2758 {
2759 if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
2760 {
2761 versionString = "Windows NT 3.51";
2762 }
2763 else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
2764 {
2765 versionString = "Windows NT 4";
2766 }
2767 else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
2768 {
2769 versionString = "Windows 2000";
2770 }
2771 else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
2772 {
2773 versionString = "Windows XP";
2774 }
2775 else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
2776 {
2777 versionString = "Windows Server 2003";
2778 }
2779 }
2780 else if( platformID == VER_PLATFORM_WIN32_CE )
2781 {
2782 versionString = "Windows CE";
2783 }
2784
2785 exit:
2786 if( inBuffer && ( inBufferSize > 0 ) )
2787 {
2788 inBufferSize -= 1;
2789 strncpy( inBuffer, versionString, inBufferSize );
2790 inBuffer[ inBufferSize ] = '\0';
2791 }
2792 return( err );
2793 }