2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
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.
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
37 Revision 1.38 2004/05/13 04:57:48 ksekar
38 Removed unnecessary FreeSearchList function
40 Revision 1.37 2004/05/13 04:54:20 ksekar
41 Unified list copy/free code. Added symetric list for
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.
49 Revision 1.35 2004/04/21 02:49:12 cheshire
50 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
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.
56 Revision 1.33 2004/04/14 23:09:29 ksekar
57 Support for TSIG signed dynamic updates.
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
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.
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.
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.
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.
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.
85 Revision 1.26 2004/01/24 04:59:16 cheshire
86 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
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.
92 Revision 1.24 2003/10/24 23:23:02 bradley
93 Removed legacy port 53 support as it is no longer needed.
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.
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.
109 Revision 1.21 2003/08/18 23:09:57 cheshire
110 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
112 Revision 1.20 2003/08/12 19:56:27 cheshire
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
119 Revision 1.18 2003/07/23 21:16:30 cheshire
120 Removed a couple of debugfs
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
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
130 Revision 1.15 2003/07/02 21:20:04 cheshire
131 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
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
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
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
145 Revision 1.11 2003/05/06 00:00:51 cheshire
146 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
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
151 Revision 1.9 2003/04/26 02:40:01 cheshire
152 Add void LogMsg( const char *format, ... )
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")
157 Revision 1.7 2003/03/15 04:40:38 cheshire
158 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
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")
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.)
169 Revision 1.4 2002/09/21 20:44:54 zarzycki
172 Revision 1.3 2002/09/20 05:50:45 bradley
173 Multicast DNS platform plugin for Win32
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).
189 #include "CommonServices.h"
190 #include "DebugServices.h"
192 #include <Iphlpapi.h>
193 #if( !TARGET_OS_WINDOWS_CE )
198 #include "mDNSClientAPI.h"
200 #include "mDNSWin32.h"
203 #pragma mark == Constants ==
206 //===========================================================================================================================
208 //===========================================================================================================================
210 #define DEBUG_NAME "[mDNSWin32] "
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
218 #define kMDNSDefaultName "My Computer"
220 #define kWinSockMajorMin 2
221 #define kWinSockMinorMin 2
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
228 #if( !TARGET_OS_WINDOWS_CE )
229 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
233 #pragma mark == Prototypes ==
236 //===========================================================================================================================
238 //===========================================================================================================================
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
);
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
);
260 // Platform Accessors
266 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
267 struct mDNSPlatformInterfaceInfo
273 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
274 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
278 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
279 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
282 #if( !TARGET_OS_WINDOWS_CE )
283 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
286 #if( TARGET_OS_WINDOWS_CE )
287 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
);
290 mDNSlocal mDNSBool
CanReceiveUnicast( void );
291 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
);
298 #pragma mark == Globals ==
301 //===========================================================================================================================
303 //===========================================================================================================================
305 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
306 mDNSs32 mDNSPlatformOneSecond
= 0;
308 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
311 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
315 PIP_ADAPTER_ADDRESSES inAdapter
,
316 PULONG outBufferSize
);
318 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
319 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
325 #pragma mark == Platform Support ==
328 //===========================================================================================================================
330 //===========================================================================================================================
332 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
338 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
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.
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
348 // Startup WinSock 2.2 or later.
350 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
351 require_noerr( err
, exit
);
353 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
354 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
356 inMDNS
->CanReceiveUnicast
= CanReceiveUnicast();
358 // Setup the HINFO HW/SW strings.
360 err
= GetWindowsVersionString( (char *) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2 );
362 inMDNS
->HIHardware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
363 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
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
);
370 // Set up the mDNS thread.
372 err
= SetupSynchronizationObjects( inMDNS
);
373 require_noerr( err
, exit
);
375 err
= SetupThread( inMDNS
);
376 require_noerr( err
, exit
);
380 mDNSCoreInitComplete( inMDNS
, err
);
385 mDNSPlatformClose( inMDNS
);
387 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
391 //===========================================================================================================================
393 //===========================================================================================================================
395 void mDNSPlatformClose( mDNS
* const inMDNS
)
399 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
402 // Tear everything down in reverse order to how it was set up.
404 err
= TearDownThread( inMDNS
);
407 err
= TearDownInterfaceList( inMDNS
);
410 err
= TearDownSynchronizationObjects( inMDNS
);
413 // Free the DLL needed for IPv6 support.
415 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
416 if( gIPHelperLibraryInstance
)
418 gGetAdaptersAddressesFunctionPtr
= NULL
;
420 FreeLibrary( gIPHelperLibraryInstance
);
421 gIPHelperLibraryInstance
= NULL
;
427 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
430 //===========================================================================================================================
431 // mDNSPlatformSendUDP
432 //===========================================================================================================================
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
)
444 mDNSInterfaceData
* ifd
;
445 struct sockaddr_storage addr
;
448 DEBUG_USE_ONLY( inMDNS
);
450 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
454 check( inInterfaceID
);
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
) );
462 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
464 if( inDstIP
->type
== mDNSAddrType_IPv4
)
466 struct sockaddr_in
* sa4
;
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
;
473 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
475 struct sockaddr_in6
* sa6
;
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.
486 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
487 err
= mStatus_BadParamErr
;
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
);
499 //===========================================================================================================================
501 //===========================================================================================================================
503 void mDNSPlatformLock( const mDNS
* const inMDNS
)
506 check( inMDNS
->p
->lockInitialized
);
508 EnterCriticalSection( &inMDNS
->p
->lock
);
511 //===========================================================================================================================
512 // mDNSPlatformUnlock
513 //===========================================================================================================================
515 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
519 check( inMDNS
->p
->lockInitialized
);
520 check( inMDNS
->p
->threadID
);
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.
525 if( GetCurrentThreadId() != inMDNS
->p
->threadID
)
529 wasSet
= SetEvent( inMDNS
->p
->wakeupEvent
);
530 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
532 LeaveCriticalSection( &inMDNS
->p
->lock
);
535 //===========================================================================================================================
536 // mDNSPlatformStrCopy
537 //===========================================================================================================================
539 void mDNSPlatformStrCopy( const void *inSrc
, void *inDst
)
544 strcpy( (char *) inDst
, (const char*) inSrc
);
547 //===========================================================================================================================
548 // mDNSPlatformStrLen
549 //===========================================================================================================================
551 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
555 return( (mDNSu32
) strlen( (const char *) inSrc
) );
558 //===========================================================================================================================
559 // mDNSPlatformMemCopy
560 //===========================================================================================================================
562 void mDNSPlatformMemCopy( const void *inSrc
, void *inDst
, mDNSu32 inSize
)
567 memcpy( inDst
, inSrc
, inSize
);
570 //===========================================================================================================================
571 // mDNSPlatformMemSame
572 //===========================================================================================================================
574 mDNSBool
mDNSPlatformMemSame( const void *inSrc
, const void *inDst
, mDNSu32 inSize
)
579 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
582 //===========================================================================================================================
583 // mDNSPlatformMemZero
584 //===========================================================================================================================
586 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
590 memset( inDst
, 0, inSize
);
593 //===========================================================================================================================
594 // mDNSPlatformMemAllocate
595 //===========================================================================================================================
597 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
603 mem
= malloc( inSize
);
609 //===========================================================================================================================
610 // mDNSPlatformMemFree
611 //===========================================================================================================================
613 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
620 //===========================================================================================================================
621 // mDNSPlatformTimeInit
622 //===========================================================================================================================
624 mDNSexport mStatus
mDNSPlatformTimeInit( mDNSs32
*outTimeNow
)
628 // No special setup is required on Windows -- we just use GetTickCount().
630 *outTimeNow
= mDNSPlatformTimeNow();
631 return( mStatus_NoError
);
634 //===========================================================================================================================
635 // mDNSPlatformTimeNow
636 //===========================================================================================================================
638 mDNSs32
mDNSPlatformTimeNow( void )
640 return( (mDNSs32
) GetTickCount() );
643 //===========================================================================================================================
645 //===========================================================================================================================
647 mDNSexport mDNSs32
mDNSPlatformUTC( void )
652 //===========================================================================================================================
653 // mDNSPlatformInterfaceNameToID
654 //===========================================================================================================================
656 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
659 mDNSInterfaceData
* ifd
;
665 // Search for an interface with the specified name,
667 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
669 if( strcmp( ifd
->name
, inName
) == 0 )
674 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
680 *outID
= (mDNSInterfaceID
) ifd
;
682 err
= mStatus_NoError
;
688 //===========================================================================================================================
689 // mDNSPlatformInterfaceIDToInfo
690 //===========================================================================================================================
692 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
695 mDNSInterfaceData
* ifd
;
701 // Search for an interface with the specified ID,
703 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
705 if( ifd
== (mDNSInterfaceData
*) inID
)
710 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
714 outInfo
->name
= ifd
->name
;
715 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
716 err
= mStatus_NoError
;
722 //===========================================================================================================================
723 // mDNSPlatformInterfaceIDfromInterfaceIndex
724 //===========================================================================================================================
726 mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS
* const inMDNS
, mDNSu32 inIndex
)
731 if( inIndex
== (mDNSu32
) ~0 )
733 id
= mDNSInterface_LocalOnly
;
735 else if( inIndex
!= 0 )
737 mDNSInterfaceData
* ifd
;
739 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
741 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
743 id
= ifd
->interfaceInfo
.InterfaceID
;
752 //===========================================================================================================================
753 // mDNSPlatformInterfaceIndexfromInterfaceID
754 //===========================================================================================================================
756 mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS
* const inMDNS
, mDNSInterfaceID inID
)
761 if( inID
== mDNSInterface_LocalOnly
)
763 index
= (mDNSu32
) ~0;
767 mDNSInterfaceData
* ifd
;
769 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
771 if( (mDNSInterfaceID
) ifd
== inID
)
773 index
= ifd
->scopeID
;
782 //===========================================================================================================================
783 // mDNSPlatformTCPConnect
784 //===========================================================================================================================
787 mDNSPlatformTCPConnect(
788 const mDNSAddr
* inDstIP
,
789 mDNSOpaque16 inDstPort
,
790 mDNSInterfaceID inInterfaceID
,
791 TCPConnectionCallback inCallback
,
795 DEBUG_UNUSED( inDstIP
);
796 DEBUG_UNUSED( inDstPort
);
797 DEBUG_UNUSED( inInterfaceID
);
798 DEBUG_UNUSED( inCallback
);
799 DEBUG_UNUSED( inContext
);
800 DEBUG_UNUSED( outSock
);
802 return( mStatus_UnsupportedErr
);
805 //===========================================================================================================================
806 // mDNSPlatformTCPCloseConnection
807 //===========================================================================================================================
809 void mDNSPlatformTCPCloseConnection( int inSock
)
811 DEBUG_UNUSED( inSock
);
814 //===========================================================================================================================
815 // mDNSPlatformReadTCP
816 //===========================================================================================================================
818 int mDNSPlatformReadTCP( int inSock
, void *inBuffer
, int inBufferSize
)
820 DEBUG_UNUSED( inSock
);
821 DEBUG_UNUSED( inBuffer
);
822 DEBUG_UNUSED( inBufferSize
);
827 //===========================================================================================================================
828 // mDNSPlatformWriteTCP
829 //===========================================================================================================================
831 int mDNSPlatformWriteTCP( int inSock
, const char *inMsg
, int inMsgSize
)
833 DEBUG_UNUSED( inSock
);
834 DEBUG_UNUSED( inMsg
);
835 DEBUG_UNUSED( inMsgSize
);
841 //===========================================================================================================================
842 // mDNSPlatformGetSearchDomainList
843 //===========================================================================================================================
846 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
848 static DNameListElem tmp
;
853 MakeDomainNameFromDNSNameString(&tmp
.name
, "local.");
857 return mDNS_CopyDNameList(&tmp
);
866 //===========================================================================================================================
868 //===========================================================================================================================
870 #if( MDNS_DEBUGMSGS )
871 void debugf_( const char *inFormat
, ... )
877 va_start( args
, inFormat
);
878 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
881 dlog( kDebugLevelInfo
, "%s\n", buffer
);
885 //===========================================================================================================================
887 //===========================================================================================================================
889 #if( MDNS_DEBUGMSGS > 1 )
890 void verbosedebugf_( const char *inFormat
, ... )
896 va_start( args
, inFormat
);
897 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
900 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
904 //===========================================================================================================================
906 //===========================================================================================================================
908 void LogMsg( const char *inFormat
, ... )
914 va_start( args
, inFormat
);
915 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
918 dlog( kDebugLevelWarning
, "%s\n", buffer
);
923 #pragma mark == Platform Internals ==
926 //===========================================================================================================================
927 // SetupSynchronizationObjects
928 //===========================================================================================================================
930 mDNSlocal mStatus
SetupSynchronizationObjects( mDNS
* const inMDNS
)
934 InitializeCriticalSection( &inMDNS
->p
->lock
);
935 inMDNS
->p
->lockInitialized
= mDNStrue
;
937 inMDNS
->p
->cancelEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
938 err
= translate_errno( inMDNS
->p
->cancelEvent
, (mStatus
) GetLastError(), kUnknownErr
);
939 require_noerr( err
, exit
);
941 inMDNS
->p
->quitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
942 err
= translate_errno( inMDNS
->p
->quitEvent
, (mStatus
) GetLastError(), kUnknownErr
);
943 require_noerr( err
, exit
);
945 inMDNS
->p
->interfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
946 err
= translate_errno( inMDNS
->p
->interfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
947 require_noerr( err
, exit
);
949 inMDNS
->p
->wakeupEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
950 err
= translate_errno( inMDNS
->p
->wakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
951 require_noerr( err
, exit
);
956 TearDownSynchronizationObjects( inMDNS
);
961 //===========================================================================================================================
962 // TearDownSynchronizationObjects
963 //===========================================================================================================================
965 mDNSlocal mStatus
TearDownSynchronizationObjects( mDNS
* const inMDNS
)
967 if( inMDNS
->p
->quitEvent
)
969 CloseHandle( inMDNS
->p
->quitEvent
);
970 inMDNS
->p
->quitEvent
= 0;
972 if( inMDNS
->p
->cancelEvent
)
974 CloseHandle( inMDNS
->p
->cancelEvent
);
975 inMDNS
->p
->cancelEvent
= 0;
977 if( inMDNS
->p
->interfaceListChangedEvent
)
979 CloseHandle( inMDNS
->p
->interfaceListChangedEvent
);
980 inMDNS
->p
->interfaceListChangedEvent
= 0;
982 if( inMDNS
->p
->wakeupEvent
)
984 CloseHandle( inMDNS
->p
->wakeupEvent
);
985 inMDNS
->p
->wakeupEvent
= 0;
987 if( inMDNS
->p
->lockInitialized
)
989 DeleteCriticalSection( &inMDNS
->p
->lock
);
990 inMDNS
->p
->lockInitialized
= mDNSfalse
;
992 return( mStatus_NoError
);
995 //===========================================================================================================================
997 //===========================================================================================================================
999 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
1002 char tempString
[ 256 ];
1006 // Set up the nice name.
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' ) )
1013 // Invalidate name so fall back to a default name.
1015 strcpy( tempString
, kMDNSDefaultName
);
1017 tempString
[ sizeof( tempString
) - 1 ] = '\0';
1019 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) strlen( tempString
);
1020 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], tempString
, inMDNS
->nicelabel
.c
[ 0 ] );
1022 // Set up the host name.
1024 ConvertUTF8PstringToRFC1034HostLabel( inMDNS
->nicelabel
.c
, &inMDNS
->hostlabel
);
1025 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
1027 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
1029 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
1031 check( inMDNS
->nicelabel
.c
[ 0 ] != 0 );
1032 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
1034 mDNS_GenerateFQDN( inMDNS
);
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 ] );
1041 //===========================================================================================================================
1042 // SetupInterfaceList
1043 //===========================================================================================================================
1045 mDNSlocal mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
1048 mDNSInterfaceData
** next
;
1049 mDNSInterfaceData
* ifd
;
1050 struct ifaddrs
* addrs
;
1052 struct ifaddrs
* loopback
;
1056 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
1062 // Tear down any existing interfaces that may be set up.
1064 TearDownInterfaceList( inMDNS
);
1066 // Set up the name of this machine.
1068 err
= SetupName( inMDNS
);
1071 // Set up the interface list change notification.
1073 err
= SetupNotifications( inMDNS
);
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.
1079 err
= getifaddrs( &addrs
);
1080 require_noerr( err
, exit
);
1083 next
= &inMDNS
->p
->interfaceList
;
1085 flagMask
= IFF_UP
| IFF_MULTICAST
| IFF_POINTTOPOINT
;
1086 flagTest
= IFF_UP
| IFF_MULTICAST
;
1088 #if( MDNS_WINDOWS_ENABLE_IPV4 )
1089 for( p
= addrs
; p
; p
= p
->ifa_next
)
1091 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
1095 if( p
->ifa_flags
& IFF_LOOPBACK
)
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
);
1106 err
= SetupInterface( inMDNS
, p
, &ifd
);
1107 require_noerr( err
, exit
);
1111 ++inMDNS
->p
->interfaceCount
;
1115 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
1117 #if( MDNS_WINDOWS_ENABLE_IPV6 )
1118 for( p
= addrs
; p
; p
= p
->ifa_next
)
1120 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
1124 if( p
->ifa_flags
& IFF_LOOPBACK
)
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
);
1135 err
= SetupInterface( inMDNS
, p
, &ifd
);
1136 require_noerr( err
, exit
);
1140 ++inMDNS
->p
->interfaceCount
;
1144 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
1146 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
1148 flagMask
|= IFF_LOOPBACK
;
1149 flagTest
|= IFF_LOOPBACK
;
1151 for( p
= addrs
; p
; p
= p
->ifa_next
)
1153 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
1157 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
1167 if( !inMDNS
->p
->interfaceList
&& loopback
)
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
);
1172 err
= SetupInterface( inMDNS
, loopback
, &ifd
);
1173 require_noerr( err
, exit
);
1177 ++inMDNS
->p
->interfaceCount
;
1183 TearDownInterfaceList( inMDNS
);
1187 freeifaddrs( addrs
);
1189 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
1193 //===========================================================================================================================
1194 // TearDownInterfaceList
1195 //===========================================================================================================================
1197 mDNSlocal mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
1200 mDNSInterfaceData
* ifd
;
1202 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
1206 // Tear down interface list change notifications.
1208 err
= TearDownNotifications( inMDNS
);
1211 // Tear down all the interfaces.
1213 while( inMDNS
->p
->interfaceList
)
1215 ifd
= inMDNS
->p
->interfaceList
;
1216 inMDNS
->p
->interfaceList
= ifd
->next
;
1218 TearDownInterface( inMDNS
, ifd
);
1220 inMDNS
->p
->interfaceCount
= 0;
1222 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
1223 return( mStatus_NoError
);
1226 //===========================================================================================================================
1228 //===========================================================================================================================
1230 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
1233 mDNSInterfaceData
* ifd
;
1237 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
1241 check( inIFA
->ifa_addr
);
1244 // Allocate memory for the interface and initialize it.
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
;
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';
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.
1263 ifd
->interfaceInfo
.McastTxRx
= mDNStrue
;
1265 #if( MDNS_WINDOWS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1266 if( inIFA
->ifa_addr
->sa_family
!= AF_INET
)
1268 const mDNSInterfaceData
* p
;
1270 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
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 ) )
1276 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
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.
1287 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
1289 #if( MDNS_WINDOWS_AAAA_OVER_IPV4 )
1290 if( inIFA
->ifa_addr
->sa_family
!= AF_INET
)
1292 mDNSInterfaceData
* ipv4IFD
;
1294 for( ipv4IFD
= inMDNS
->p
->interfaceList
; ipv4IFD
; ipv4IFD
= ipv4IFD
->next
)
1296 if( strcmp( ipv4IFD
->name
, ifd
->name
) == 0 )
1298 ipv4IFD
->scopeID
= ifd
->scopeID
;
1299 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
1300 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ipv4IFD
;
1307 // Set up a socket for this interface (if needed).
1309 if( ifd
->interfaceInfo
.McastTxRx
)
1311 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, &sock
);
1312 require_noerr( err
, exit
);
1314 ifd
->defaultAddr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
1316 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
1318 #if( !TARGET_OS_WINDOWS_CE )
1322 err
= WSAIoctl( sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
),
1323 &ifd
->wsaRecvMsgFunctionPtr
, sizeof( ifd
->wsaRecvMsgFunctionPtr
), &size
, NULL
, NULL
);
1326 ifd
->wsaRecvMsgFunctionPtr
= NULL
;
1331 // Set up the read pending event and associate it so we can block until data is available for this socket.
1333 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1334 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1335 require_noerr( err
, exit
);
1337 err
= WSAEventSelect( ifd
->sock
, ifd
->readPendingEvent
, FD_READ
);
1338 require_noerr( err
, exit
);
1342 // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
1344 ifd
->readPendingEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1345 err
= translate_errno( ifd
->readPendingEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1346 require_noerr( err
, exit
);
1349 // Register this interface with mDNS.
1351 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
1352 require_noerr( err
, exit
);
1354 ifd
->interfaceInfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1356 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
);
1357 require_noerr( err
, exit
);
1358 ifd
->hostRegistered
= mDNStrue
;
1360 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
1370 TearDownInterface( inMDNS
, ifd
);
1372 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
1376 //===========================================================================================================================
1377 // TearDownInterface
1378 //===========================================================================================================================
1380 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
1387 // Deregister this interface with mDNS.
1389 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
1391 if( inIFD
->hostRegistered
)
1393 inIFD
->hostRegistered
= mDNSfalse
;
1394 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
);
1397 // Tear down the multicast socket.
1399 if( inIFD
->readPendingEvent
)
1401 CloseHandle( inIFD
->readPendingEvent
);
1402 inIFD
->readPendingEvent
= 0;
1406 inIFD
->sock
= kInvalidSocketRef
;
1407 if( IsValidSocket( sock
) )
1409 close_compat( sock
);
1412 // Free the memory used by the interface info.
1415 return( mStatus_NoError
);
1418 //===========================================================================================================================
1420 //===========================================================================================================================
1422 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, SocketRef
*outSocketRef
)
1428 DEBUG_UNUSED( inMDNS
);
1430 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
1432 check( outSocketRef
);
1434 // Set up an IPv4 or IPv6 UDP socket.
1436 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1437 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
1438 require_noerr( err
, exit
);
1440 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets.
1443 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
1444 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1446 if( inAddr
->sa_family
== AF_INET
)
1449 struct sockaddr_in sa4
;
1450 struct ip_mreq mreqv4
;
1452 // Bind to the multicast DNS port 5353.
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
;
1460 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
1461 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1463 // Turn on option to receive destination addresses and receiving interface.
1466 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
1467 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1469 // Join the all-DNS multicast group so we receive Multicast DNS packets.
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
);
1476 // Specify the interface to send multicast packets on this socket.
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
);
1482 // Send unicast packets with TTL 255 (helps against spoofing).
1485 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
1486 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1488 // Send multicast packets with TTL 255 (helps against spoofing).
1491 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
1492 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1494 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
1497 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
1498 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1500 else if( inAddr
->sa_family
== AF_INET6
)
1502 struct sockaddr_in6
* sa6p
;
1503 struct sockaddr_in6 sa6
;
1504 struct ipv6_mreq mreqv6
;
1506 sa6p
= (struct sockaddr_in6
*) inAddr
;
1508 // Bind to the multicast DNS port 5353.
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
;
1517 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
1518 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1520 // Turn on option to receive destination addresses and receiving interface.
1523 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
1524 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1526 // Turn on option to receive TTL so we can check for spoofing.
1529 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, (char *) &option
, sizeof( option
) );
1530 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
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).
1536 #if( defined( IPV6_V6ONLY ) )
1538 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
1539 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1542 // Join the all-DNS multicast group so we receive Multicast DNS packets.
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
);
1549 // Specify the interface to send multicast packets on this socket.
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
);
1555 // Send unicast packets with TTL 255 (helps against spoofing).
1558 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
1559 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1561 // Send multicast packets with TTL 255 (helps against spoofing).
1564 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
1565 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1567 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
1570 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
1571 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1575 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
1576 err
= kUnsupportedErr
;
1582 *outSocketRef
= sock
;
1583 sock
= kInvalidSocketRef
;
1584 err
= mStatus_NoError
;
1587 if( IsValidSocket( sock
) )
1589 close_compat( sock
);
1594 //===========================================================================================================================
1596 //===========================================================================================================================
1598 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
1605 if( inSA
->sa_family
== AF_INET
)
1607 struct sockaddr_in
* sa4
;
1609 sa4
= (struct sockaddr_in
*) inSA
;
1610 outIP
->type
= mDNSAddrType_IPv4
;
1611 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1614 outPort
->NotAnInteger
= sa4
->sin_port
;
1616 err
= mStatus_NoError
;
1618 else if( inSA
->sa_family
== AF_INET6
)
1620 struct sockaddr_in6
* sa6
;
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
) )
1627 outIP
->ip
.v6
.w
[ 1 ] = 0;
1631 outPort
->NotAnInteger
= sa6
->sin6_port
;
1633 err
= mStatus_NoError
;
1637 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
1638 err
= mStatus_BadParamErr
;
1643 //===========================================================================================================================
1644 // SetupNotifications
1645 //===========================================================================================================================
1647 mDNSlocal mStatus
SetupNotifications( mDNS
* const inMDNS
)
1651 unsigned long param
;
1656 // Register to listen for address list changes.
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
;
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.
1667 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
1668 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
1669 require_noerr( err
, exit
);
1673 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1676 check( errno_compat() == WSAEWOULDBLOCK
);
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
);
1686 TearDownNotifications( inMDNS
);
1691 //===========================================================================================================================
1692 // TearDownNotifications
1693 //===========================================================================================================================
1695 mDNSlocal mStatus
TearDownNotifications( mDNS
* const inMDNS
)
1697 if( IsValidSocket( inMDNS
->p
->interfaceListChangedSocket
) )
1699 close_compat( inMDNS
->p
->interfaceListChangedSocket
);
1700 inMDNS
->p
->interfaceListChangedSocket
= kInvalidSocketRef
;
1702 return( mStatus_NoError
);
1709 //===========================================================================================================================
1711 //===========================================================================================================================
1713 mDNSlocal mStatus
SetupThread( mDNS
* const inMDNS
)
1716 HANDLE threadHandle
;
1720 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread\n" );
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.
1725 inMDNS
->p
->initEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1726 err
= translate_errno( inMDNS
->p
->initEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1727 require_noerr( err
, exit
);
1729 inMDNS
->p
->initStatus
= mStatus_Invalid
;
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>.
1734 threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, ProcessingThread
, inMDNS
, 0, &threadID
);
1735 err
= translate_errno( threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1736 require_noerr( err
, exit
);
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
);
1745 if( inMDNS
->p
->initEvent
)
1747 CloseHandle( inMDNS
->p
->initEvent
);
1748 inMDNS
->p
->initEvent
= 0;
1750 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up thread done (err=%d %m)\n", err
, err
);
1754 //===========================================================================================================================
1756 //===========================================================================================================================
1758 mDNSlocal mStatus
TearDownThread( const mDNS
* const inMDNS
)
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.
1763 if( inMDNS
->p
->cancelEvent
)
1768 wasSet
= SetEvent( inMDNS
->p
->cancelEvent
);
1769 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
1771 if( inMDNS
->p
->quitEvent
)
1773 result
= WaitForSingleObject( inMDNS
->p
->quitEvent
, 5 * 1000 );
1774 check_translated_errno( result
== WAIT_OBJECT_0
, GetLastError(), kUnknownErr
);
1777 return( mStatus_NoError
);
1780 //===========================================================================================================================
1782 //===========================================================================================================================
1784 mDNSlocal
unsigned WINAPI
ProcessingThread( LPVOID inParam
)
1796 m
= (mDNS
*) inParam
;
1797 err
= ProcessingThreadInitialize( m
);
1798 require_noerr( err
, exit
);
1803 // Set up the list of objects we'll be waiting on.
1807 err
= ProcessingThreadSetupWaitList( m
, &waitList
, &waitListCount
);
1808 require_noerr( err
, exit
);
1810 // Main processing loop.
1814 // Give the mDNS core a chance to do its work and determine next event time.
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
;
1821 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1823 result
= WaitForMultipleObjects( (DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) interval
);
1824 if( result
== WAIT_TIMEOUT
)
1826 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1828 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
1831 else if( result
== kWaitListCancelEvent
)
1833 // Cancel event. Set the done flag and break to exit.
1835 dlog( kDebugLevelVerbose
, DEBUG_NAME
"canceling...\n" );
1839 else if( result
== kWaitListInterfaceListChangedEvent
)
1841 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1843 ProcessingThreadInterfaceListChanged( m
);
1846 else if( result
== kWaitListWakeupEvent
)
1848 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
1850 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"wakeup for mDNS_Execute\n" );
1857 // Socket data available event. Determine which socket and process the packet.
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
) )
1864 HANDLE signaledObject
;
1866 mDNSInterfaceData
* ifd
;
1868 signaledObject
= waitList
[ waitItemIndex
];
1871 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1873 if( ifd
->readPendingEvent
== signaledObject
)
1875 ProcessingThreadProcessPacket( m
, ifd
, ifd
->sock
);
1883 // Unexpected wait result.
1885 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1890 // Release the wait list.
1900 // Signal the quit event to indicate that the thread is finished.
1903 wasSet
= SetEvent( m
->p
->quitEvent
);
1904 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
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>.
1909 _endthreadex_compat( 0 );
1913 //===========================================================================================================================
1914 // ProcessingThreadInitialize
1915 //===========================================================================================================================
1917 mDNSlocal mStatus
ProcessingThreadInitialize( mDNS
* const inMDNS
)
1922 inMDNS
->p
->threadID
= GetCurrentThreadId();
1924 err
= SetupInterfaceList( inMDNS
);
1925 require_noerr( err
, exit
);
1930 TearDownInterfaceList( inMDNS
);
1932 inMDNS
->p
->initStatus
= err
;
1934 wasSet
= SetEvent( inMDNS
->p
->initEvent
);
1935 check_translated_errno( wasSet
, GetLastError(), kUnknownErr
);
1939 //===========================================================================================================================
1940 // ProcessingThreadSetupWaitList
1941 //===========================================================================================================================
1943 mDNSlocal mStatus
ProcessingThreadSetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
1948 HANDLE
* waitItemPtr
;
1949 mDNSInterfaceData
* ifd
;
1951 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list\n" );
1954 check( outWaitList
);
1955 check( outWaitListCount
);
1957 // Allocate an array to hold all the objects to wait on.
1959 waitListCount
= kWaitListFixedItemCount
+ inMDNS
->p
->interfaceCount
;
1960 waitList
= (HANDLE
*) malloc( waitListCount
* sizeof( *waitList
) );
1961 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
1962 waitItemPtr
= waitList
;
1964 // Add the fixed wait items to the beginning of the list.
1966 *waitItemPtr
++ = inMDNS
->p
->cancelEvent
;
1967 *waitItemPtr
++ = inMDNS
->p
->interfaceListChangedEvent
;
1968 *waitItemPtr
++ = inMDNS
->p
->wakeupEvent
;
1970 // Append all the dynamic wait items to the list.
1972 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
1974 *waitItemPtr
++ = ifd
->readPendingEvent
;
1976 check( (int)( waitItemPtr
- waitList
) == waitListCount
);
1978 *outWaitList
= waitList
;
1979 *outWaitListCount
= waitListCount
;
1981 err
= mStatus_NoError
;
1988 dlog( kDebugLevelTrace
, DEBUG_NAME
"thread setting up wait list done (err=%d %m)\n", err
, err
);
1992 //===========================================================================================================================
1993 // ProcessingThreadProcessPacket
1994 //===========================================================================================================================
1996 mDNSlocal
void ProcessingThreadProcessPacket( mDNS
*inMDNS
, mDNSInterfaceData
*inIFD
, SocketRef inSock
)
2004 struct sockaddr_storage addr
;
2011 check( IsValidSocket( inSock
) );
2013 // Set up the default in case the packet info options are not supported or reported correctly.
2015 dstAddr
= inIFD
->defaultAddr
;
2016 dstPort
= MulticastDNSPort
;
2019 #if( !TARGET_OS_WINDOWS_CE )
2020 if( inIFD
->wsaRecvMsgFunctionPtr
)
2024 uint8_t controlBuffer
[ 128 ];
2026 LPWSACMSGHDR header
;
2028 // Set up the buffer and read the packet.
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
);
2040 err
= inIFD
->wsaRecvMsgFunctionPtr( inSock
, &msg
, &size
, NULL
, NULL
);
2041 err
= translate_errno( err
== 0, (OSStatus
) GetLastError(), kUnknownErr
);
2042 require_noerr( err
, exit
);
2045 // Parse the control information. Reject packets received on the wrong interface.
2047 for( header
= WSA_CMSG_FIRSTHDR( &msg
); header
; header
= WSA_CMSG_NXTHDR( &msg
, header
) )
2049 if( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
2051 IN_PKTINFO
* ipv4PacketInfo
;
2053 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
2054 require_action( ipv4PacketInfo
->ipi_ifindex
== ( inIFD
->index
>> 8 ), exit
, err
= kMismatchErr
);
2056 dstAddr
.type
= mDNSAddrType_IPv4
;
2057 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
2059 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
2061 IN6_PKTINFO
* ipv6PacketInfo
;
2063 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
2064 require_action( ipv6PacketInfo
->ipi6_ifindex
== inIFD
->index
, exit
, err
= kMismatchErr
);
2066 dstAddr
.type
= mDNSAddrType_IPv6
;
2067 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
2069 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_HOPLIMIT
) )
2071 ttl
= (mDNSu8
) *( (int *) WSA_CMSG_DATA( header
) );
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
);
2085 SockAddrToMDNSAddr( (struct sockaddr
*) &addr
, &srcAddr
, &srcPort
);
2087 // Dispatch the packet to mDNS.
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" );
2096 end
= ( (mDNSu8
*) &packet
) + n
;
2097 mDNSCoreReceive( inMDNS
, &packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, inIFD
->interfaceInfo
.InterfaceID
, ttl
);
2103 //===========================================================================================================================
2104 // ProcessingThreadInterfaceListChanged
2105 //===========================================================================================================================
2107 mDNSlocal
void ProcessingThreadInterfaceListChanged( mDNS
*inMDNS
)
2111 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
2114 mDNSPlatformLock( inMDNS
);
2116 // Tear down the existing interfaces and set up new ones using the new IP info.
2118 err
= TearDownInterfaceList( inMDNS
);
2121 err
= SetupInterfaceList( inMDNS
);
2124 mDNSPlatformUnlock( inMDNS
);
2126 // Inform clients of the change.
2128 if( inMDNS
->MainCallback
)
2130 inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
2133 // Force mDNS to update.
2135 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
);
2140 #pragma mark == Utilities ==
2143 //===========================================================================================================================
2145 //===========================================================================================================================
2147 int getifaddrs( struct ifaddrs
**outAddrs
)
2151 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
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.
2156 if( !gIPHelperLibraryInstance
)
2158 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
2159 if( gIPHelperLibraryInstance
)
2161 gGetAdaptersAddressesFunctionPtr
=
2162 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
2163 if( !gGetAdaptersAddressesFunctionPtr
)
2167 ok
= FreeLibrary( gIPHelperLibraryInstance
);
2168 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
2169 gIPHelperLibraryInstance
= NULL
;
2174 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
2176 if( gGetAdaptersAddressesFunctionPtr
)
2178 err
= getifaddrs_ipv6( outAddrs
);
2179 require_noerr( err
, exit
);
2183 err
= getifaddrs_ipv4( outAddrs
);
2184 require_noerr( err
, exit
);
2187 #elif( !TARGET_OS_WINDOWS_CE )
2189 err
= getifaddrs_ipv4( outAddrs
);
2190 require_noerr( err
, exit
);
2194 err
= getifaddrs_ce( outAddrs
);
2195 require_noerr( err
, exit
);
2203 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
2204 //===========================================================================================================================
2206 //===========================================================================================================================
2208 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
2213 struct ifaddrs
* head
;
2214 struct ifaddrs
** next
;
2215 IP_ADAPTER_ADDRESSES
* iaaList
;
2217 IP_ADAPTER_ADDRESSES
* iaa
;
2219 struct ifaddrs
* ifa
;
2221 check( gGetAdaptersAddressesFunctionPtr
);
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.
2231 flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
2236 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
2237 check( err
== ERROR_BUFFER_OVERFLOW
);
2238 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
2240 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
2241 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
2243 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
2244 if( err
== ERROR_SUCCESS
) break;
2249 require( i
< 100, exit
);
2250 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
2253 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
2255 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
2257 if( iaa
->IfIndex
> 0xFFFFFF )
2259 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
2261 if( iaa
->Ipv6IfIndex
> 0xFF )
2263 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
2266 // Skip psuedo and tunnel interfaces.
2268 if( ( iaa
->Ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
2273 // Add each address as a separate interface to emulate the way getifaddrs works.
2275 for( addr
= iaa
->FirstUnicastAddress
; addr
; addr
= addr
->Next
)
2277 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
2278 require_action( ifa
, exit
, err
= WSAENOBUFS
);
2281 next
= &ifa
->ifa_next
;
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
);
2290 // Get interface flags.
2293 if( iaa
->OperStatus
== IfOperStatusUp
)
2295 ifa
->ifa_flags
|= IFF_UP
;
2297 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
)
2299 ifa
->ifa_flags
|= IFF_LOOPBACK
;
2301 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) )
2303 ifa
->ifa_flags
|= IFF_MULTICAST
;
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.
2310 switch( addr
->Address
.lpSockaddr
->sa_family
)
2313 ifa
->ifa_extra
.index
= iaa
->IfIndex
<< 8;
2317 ifa
->ifa_extra
.index
= iaa
->Ipv6IfIndex
;
2326 switch( addr
->Address
.lpSockaddr
->sa_family
)
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
);
2348 err
= ERROR_SUCCESS
;
2353 freeifaddrs( head
);
2359 return( (int) err
);
2361 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
2363 #if( !TARGET_OS_WINDOWS_CE )
2364 //===========================================================================================================================
2366 //===========================================================================================================================
2368 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
2374 INTERFACE_INFO
* buffer
;
2375 INTERFACE_INFO
* tempBuffer
;
2376 INTERFACE_INFO
* ifInfo
;
2379 struct ifaddrs
* head
;
2380 struct ifaddrs
** next
;
2381 struct ifaddrs
* ifa
;
2383 sock
= INVALID_SOCKET
;
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.
2392 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2393 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2394 require_noerr( err
, exit
);
2397 size
= 16 * sizeof( INTERFACE_INFO
);
2400 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
2401 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
2402 buffer
= tempBuffer
;
2404 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
2411 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
2413 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
2415 check( actualSize
<= size
);
2416 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
2417 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
2419 // Process the raw interface list and build a linked list of IPv4 interfaces.
2421 for( i
= 0; i
< n
; ++i
)
2423 ifInfo
= &buffer
[ i
];
2424 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
2429 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
2430 require_action( ifa
, exit
, err
= WSAENOBUFS
);
2433 next
= &ifa
->ifa_next
;
2437 ifa
->ifa_name
= (char *) malloc( 16 );
2438 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
2439 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
2441 // Get interface flags.
2443 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
2447 switch( ifInfo
->iiAddress
.Address
.sa_family
)
2451 struct sockaddr_in
* sa4
;
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
) );
2464 // Emulate an interface index.
2466 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
2481 freeifaddrs( head
);
2487 if( sock
!= INVALID_SOCKET
)
2489 closesocket( sock
);
2493 #endif // !TARGET_OS_WINDOWS_CE )
2495 #if( TARGET_OS_WINDOWS_CE )
2496 //===========================================================================================================================
2498 //===========================================================================================================================
2500 mDNSlocal
int getifaddrs_ce( struct ifaddrs
**outAddrs
)
2506 SOCKET_ADDRESS_LIST
* addressList
;
2507 struct ifaddrs
* head
;
2508 struct ifaddrs
** next
;
2509 struct ifaddrs
* ifa
;
2513 sock
= kInvalidSocketRef
;
2518 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
2520 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2521 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2522 require_noerr( err
, exit
);
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.
2527 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
2530 WSAIoctl( sock
, SIO_ADDRESS_LIST_QUERY
, NULL
, 0, NULL
, 0, &size
, NULL
, NULL
);
2531 require_action( size
> 0, exit
, err
= -1 );
2534 buffer
= calloc( 1, size
);
2535 require_action( buffer
, exit
, err
= -1 );
2537 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
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
;
2543 // Process the raw interface list and build a linked list of interfaces.
2545 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
2547 n
= addressList
->iAddressCount
;
2552 for( i
= 0; i
< n
; ++i
)
2554 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
2555 require_action( ifa
, exit
, err
= WSAENOBUFS
);
2558 next
= &ifa
->ifa_next
;
2562 ifa
->ifa_name
= (char *) malloc( 16 );
2563 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
2564 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
2566 // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
2568 ifa
->ifa_flags
= IFF_UP
| IFF_MULTICAST
;
2572 switch( addressList
->Address
[ i
].lpSockaddr
->sa_family
)
2576 struct sockaddr_in
* sa4
;
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
) );
2602 freeifaddrs( head
);
2608 if( sock
!= INVALID_SOCKET
)
2610 closesocket( sock
);
2614 #endif // TARGET_OS_WINDOWS_CE )
2616 //===========================================================================================================================
2618 //===========================================================================================================================
2620 void freeifaddrs( struct ifaddrs
*inIFAs
)
2625 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
2627 for( p
= inIFAs
; p
; p
= q
)
2633 free( p
->ifa_name
);
2638 free( p
->ifa_addr
);
2641 if( p
->ifa_netmask
)
2643 free( p
->ifa_netmask
);
2644 p
->ifa_netmask
= NULL
;
2646 if( p
->ifa_broadaddr
)
2648 free( p
->ifa_broadaddr
);
2649 p
->ifa_broadaddr
= NULL
;
2651 if( p
->ifa_dstaddr
)
2653 free( p
->ifa_dstaddr
);
2654 p
->ifa_dstaddr
= NULL
;
2658 free( p
->ifa_data
);
2665 //===========================================================================================================================
2666 // CanReceiveUnicast
2667 //===========================================================================================================================
2669 mDNSlocal mDNSBool
CanReceiveUnicast( void )
2673 struct sockaddr_in addr
;
2675 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
2677 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
2678 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2679 ok
= IsValidSocket( sock
);
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
);
2687 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
2688 close_compat( sock
);
2691 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
2695 //===========================================================================================================================
2696 // GetWindowsVersionString
2697 //===========================================================================================================================
2699 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
2701 #if( !defined( VER_PLATFORM_WIN32_CE ) )
2702 #define VER_PLATFORM_WIN32_CE 3
2706 OSVERSIONINFO osInfo
;
2708 const char * versionString
;
2714 versionString
= "unknown Windows version";
2716 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
2717 ok
= GetVersionEx( &osInfo
);
2718 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
2719 require_noerr( err
, exit
);
2721 platformID
= osInfo
.dwPlatformId
;
2722 majorVersion
= osInfo
.dwMajorVersion
;
2723 minorVersion
= osInfo
.dwMinorVersion
;
2724 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
2726 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
2728 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
2730 versionString
= "Windows 95";
2732 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
2734 versionString
= "Windows 95 SP1";
2736 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
2738 versionString
= "Windows 95 OSR2";
2740 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
2742 versionString
= "Windows 98";
2744 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
2746 versionString
= "Windows 98 SP1";
2748 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
2750 versionString
= "Windows 98 SE";
2752 else if( minorVersion
== 90 )
2754 versionString
= "Windows ME";
2757 else if( platformID
== VER_PLATFORM_WIN32_NT
)
2759 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
2761 versionString
= "Windows NT 3.51";
2763 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
2765 versionString
= "Windows NT 4";
2767 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
2769 versionString
= "Windows 2000";
2771 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
2773 versionString
= "Windows XP";
2775 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
2777 versionString
= "Windows Server 2003";
2780 else if( platformID
== VER_PLATFORM_WIN32_CE
)
2782 versionString
= "Windows CE";
2786 if( inBuffer
&& ( inBufferSize
> 0 ) )
2789 strncpy( inBuffer
, versionString
, inBufferSize
);
2790 inBuffer
[ inBufferSize
] = '\0';