]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/mDNSWin32.c
mDNSResponder-58.8.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / mDNSWin32.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: mDNSWin32.c,v $
26 Revision 1.22.2.1 2004/04/03 05:26:07 bradley
27 Integrated changes from TOT to remove legacy port 53 support.
28
29 Revision 1.24 2003/10/24 23:23:02 bradley
30 Removed legacy port 53 support as it is no longer needed.
31
32 Revision 1.23 2003/10/14 03:26:12 bradley
33 Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
34
35 Revision 1.22 2003/08/20 06:21:25 bradley
36 Updated to latest internal version of the Rendezvous for Windows platform plugin: Added support
37 for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
38 restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
39 the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
40 enable ThreadID improvement to wakeup notification; Define platform support structure locally to
41 allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
42 structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
43 platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
44 Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
45
46 Revision 1.21 2003/08/18 23:09:57 cheshire
47 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformTimeNow()
48
49 Revision 1.20 2003/08/12 19:56:27 cheshire
50 Update to APSL 2.0
51
52 Revision 1.19 2003/08/05 23:58:18 cheshire
53 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
54 Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
55
56 Revision 1.18 2003/07/23 21:16:30 cheshire
57 Removed a couple of debugfs
58
59 Revision 1.17 2003/07/23 02:23:01 cheshire
60 Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
61 "ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
62
63 Revision 1.16 2003/07/19 03:15:16 cheshire
64 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
65 and add the obvious trivial implementations to each platform support layer
66
67 Revision 1.15 2003/07/02 21:20:04 cheshire
68 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
69
70 Revision 1.14 2003/05/26 03:21:30 cheshire
71 Tidy up address structure naming:
72 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
73 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
74 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
75
76 Revision 1.13 2003/05/26 03:01:28 cheshire
77 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
78
79 Revision 1.12 2003/05/06 21:06:05 cheshire
80 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
81
82 Revision 1.11 2003/05/06 00:00:51 cheshire
83 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
84
85 Revision 1.10 2003/04/29 00:06:09 cheshire
86 <rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
87
88 Revision 1.9 2003/04/26 02:40:01 cheshire
89 Add void LogMsg( const char *format, ... )
90
91 Revision 1.8 2003/03/22 02:57:44 cheshire
92 Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
93
94 Revision 1.7 2003/03/15 04:40:38 cheshire
95 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
96
97 Revision 1.6 2003/02/21 01:54:10 cheshire
98 Bug #: 3099194 mDNSResponder needs performance improvements
99 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
100
101 Revision 1.5 2003/02/20 00:59:03 cheshire
102 Brought Windows code up to date so it complies with
103 Josh Graessley's interface changes for IPv6 support.
104 (Actual support for IPv6 on Windows will come later.)
105
106 Revision 1.4 2002/09/21 20:44:54 zarzycki
107 Added APSL info
108
109 Revision 1.3 2002/09/20 05:50:45 bradley
110 Multicast DNS platform plugin for Win32
111
112 */
113
114 #if( defined( _MSC_VER ) )
115 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
116 #endif
117
118 #if( !defined( WIN32_LEAN_AND_MEAN ) )
119 #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
120 #endif
121
122 #include <stdarg.h>
123 #include <stddef.h>
124 #include <stdio.h>
125 #include <stdlib.h>
126 #include <string.h>
127
128 #include <windows.h>
129 #include <winsock2.h>
130 #include <Ws2tcpip.h>
131
132 #if( !defined( _WIN32_WCE ) ) // Windows CE does not have process.h.
133 #include <process.h>
134 #endif
135
136 #if( DEBUG )
137 #define mDNSlocal
138 #endif
139
140 #include "mDNSClientAPI.h"
141 #include "mDNSPlatformFunctions.h"
142
143 #include "mDNSWin32.h"
144
145 #if 0
146 #pragma mark == Constants ==
147 #endif
148
149 //===========================================================================================================================
150 // Constants
151 //===========================================================================================================================
152
153 #define DEBUG_NAME "[mDNS] "
154
155 #if( !defined( MDNS_DEBUG_SIGNATURE ) )
156 #define MDNS_DEBUG_SIGNATURE "mDNS"
157 #endif
158
159 #define kMDNSDefaultName "My Computer"
160
161 #define kWinSockMajorMin 2
162 #define kWinSockMinorMin 2
163
164 #define kWaitListCancelEvent ( WAIT_OBJECT_0 + 0 )
165 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
166 #define kWaitListWakeupEvent ( WAIT_OBJECT_0 + 2 )
167 #define kWaitListFixedItemCount 3
168
169 #if 0
170 #pragma mark == Macros - Debug ==
171 #endif
172
173 //===========================================================================================================================
174 // Macros - Debug
175 //===========================================================================================================================
176
177 #define MDNS_UNUSED( X ) (void)( X )
178
179 #define kDebugLevelMask 0x0000FFFFL
180 #define kDebugLevelChatty 100L
181 #define kDebugLevelVerbose 500L
182 #define kDebugLevelTrace 800L
183 #define kDebugLevelInfo 1000L
184 #define kDebugLevelRareInfo 2000L
185 #define kDebugLevelNotice 3000L
186 #define kDebugLevelWarning 4000L
187 #define kDebugLevelAllowedError 5000L
188 #define kDebugLevelAssert 6000L
189 #define kDebugLevelRequire 7000L
190 #define kDebugLevelError 8000L
191 #define kDebugLevelCritical 9000L
192 #define kDebugLevelCriticalError kDebugLevelCritical // DEPRECATED
193 #define kDebugLevelAlert 10000L
194 #define kDebugLevelEmergency 11000L
195 #define kDebugLevelTragic 12000L
196 #define kDebugLevelAny 0x0000FFFFL
197
198 #if( defined( __MWERKS__ ) || defined( __GNUC__ ) )
199 #define __ROUTINE__ __FUNCTION__
200 #else
201 // Apple and Symantec compilers don't support the C99/GCC extensions yet.
202
203 #define __ROUTINE__ NULL
204 #endif
205
206 #if( MDNS_DEBUGMSGS )
207 #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION ) \
208 mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, 0, ( ASSERT_STRING ), NULL, ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
209
210 #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION ) \
211 mDNSPlatformPrintAssert( MDNS_DEBUG_SIGNATURE, ( ERR ), ( ASSERT_STRING ), ( ERROR_STRING ), \
212 ( FILENAME ), ( LINE_NUMBER ), ( FUNCTION ) )
213
214 #define dlog mDNSPlatformDebugLog
215 #else
216 #define debug_print_assert( ASSERT_STRING, FILENAME, LINE_NUMBER, FUNCTION )
217
218 #define debug_print_assert_err( ERR, ASSERT_STRING, ERROR_STRING, FILENAME, LINE_NUMBER, FUNCTION )
219
220 #define dlog while( 0 )
221 #endif
222
223 ///
224 /// The following debugging macros emulate those available on Mac OS in AssertMacros.h/Debugging.h.
225 ///
226
227 // checks
228
229 #define check( X ) \
230 do { \
231 if( !( X ) ) { \
232 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
233 } \
234 } while( 0 )
235
236 #define check_noerr( ERR ) \
237 do { \
238 if( ( ERR ) != 0 ) { \
239 debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
240 } \
241 } while( 0 )
242
243 #define check_errno( ERR, ERRNO ) \
244 do { \
245 int localErr; \
246 \
247 localErr = (int)( ERR ); \
248 if( localErr < 0 ) { \
249 int localErrno; \
250 \
251 localErrno = ( ERRNO ); \
252 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
253 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
254 } \
255 } while( 0 )
256
257 // requires
258
259 #define require( X, LABEL ) \
260 do { \
261 if( !( X ) ) { \
262 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
263 goto LABEL; \
264 } \
265 } while( 0 )
266
267 #define require_quiet( X, LABEL ) \
268 do { \
269 if( !( X ) ) { \
270 goto LABEL; \
271 } \
272 } while( 0 )
273
274 #define require_action( X, LABEL, ACTION ) \
275 do { \
276 if( !( X ) ) { \
277 debug_print_assert( #X, __FILE__, __LINE__, __ROUTINE__ ); \
278 { ACTION; } \
279 goto LABEL; \
280 } \
281 } while( 0 )
282
283 #define require_action_quiet( X, LABEL, ACTION ) \
284 do { \
285 if( !( X ) ) { \
286 { ACTION; } \
287 goto LABEL; \
288 } \
289 } while( 0 )
290
291 #define require_noerr( ERR, LABEL ) \
292 do { \
293 if( ( ERR ) != 0 ) { \
294 debug_print_assert_err( ( ERR ), #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
295 goto LABEL; \
296 } \
297 } while( 0 )
298
299 #define require_noerr_quiet( ERR, LABEL ) \
300 do { \
301 if( ( ERR ) != 0 ) { \
302 goto LABEL; \
303 } \
304 } while( 0 )
305
306 #define require_errno( ERR, ERRNO, LABEL ) \
307 do { \
308 int localErr; \
309 \
310 localErr = (int)( ERR ); \
311 if( localErr < 0 ) { \
312 int localErrno; \
313 \
314 localErrno = ( ERRNO ); \
315 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
316 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
317 goto LABEL; \
318 } \
319 } while( 0 )
320
321 #define require_errno_action( ERR, ERRNO, LABEL, ACTION ) \
322 do { \
323 int localErr; \
324 \
325 localErr = (int)( ERR ); \
326 if( localErr < 0 ) { \
327 int localErrno; \
328 \
329 localErrno = ( ERRNO ); \
330 localErr = ( localErrno != 0 ) ? localErrno : localErr; \
331 debug_print_assert_err( localErr, #ERR, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
332 { ACTION; } \
333 goto LABEL; \
334 } \
335 } while( 0 )
336
337 #if 0
338 #pragma mark == Macros - General ==
339 #endif
340
341 //===========================================================================================================================
342 // Macros - General
343 //===========================================================================================================================
344
345 #define kInvalidSocketRef INVALID_SOCKET
346 #define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
347 #define close_compat( X ) closesocket( X )
348 #define errno_compat() WSAGetLastError()
349
350 // _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking
351 // resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to
352 // CreateThread on Windows CE.
353
354 #if( defined( _WIN32_WCE ) )
355 #define _beginthreadex( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR ) \
356 CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS, \
357 (LPDWORD) THREAD_ID_PTR )
358
359 #define _endthreadex( RESULT )
360 #endif
361
362 #if 0
363 #pragma mark == Prototypes ==
364 #endif
365
366 //===========================================================================================================================
367 // Prototypes
368 //===========================================================================================================================
369
370 #if( MDNS_DEBUGMSGS )
371 mDNSlocal void mDNSPlatformDebugLog( unsigned long inLevel, const char *inFormat, ... );
372 mDNSlocal void
373 mDNSPlatformPrintAssert(
374 const char * inSignature,
375 long inError,
376 const char * inAssertionString,
377 const char * inErrorString,
378 const char * inFileName,
379 unsigned long inLineNumber,
380 const char * inFunction );
381 #endif
382
383 mDNSlocal mStatus SetupSynchronizationObjects( mDNS * const inMDNS );
384 mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS );
385 mDNSlocal mStatus SetupName( mDNS * const inMDNS );
386 mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS );
387 mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS );
388 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct sockaddr_in *inAddress, mDNSInterfaceData **outIFD );
389 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
390 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS,
391 const struct sockaddr_in * inAddress,
392 SocketRef * outSocketRef );
393 mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS );
394 mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS );
395
396 mDNSlocal mStatus SetupThread( mDNS * const inMDNS );
397 mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS );
398 mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam );
399 mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS );
400 mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
401 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSocketRef );
402 mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
403
404 // Platform Accessors
405
406 #ifdef __cplusplus
407 extern "C" {
408 #endif
409
410 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
411 struct mDNSPlatformInterfaceInfo
412 {
413 const char * name;
414 mDNSAddr ip;
415 };
416
417 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
418 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
419
420 #ifdef __cplusplus
421 }
422 #endif
423
424 #if 0
425 #pragma mark == Globals ==
426 #endif
427
428 //===========================================================================================================================
429 // Globals
430 //===========================================================================================================================
431
432 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
433 mDNSs32 mDNSPlatformOneSecond = 0;
434
435 #if( MDNS_DEBUGMSGS )
436 mDNSlocal unsigned long gDebugLevel = kDebugLevelInfo + 1;
437 #endif
438
439 #if 0
440 #pragma mark -
441 #pragma mark == Platform Support APIs ==
442 #endif
443
444 //===========================================================================================================================
445 // mDNSPlatformInit
446 //===========================================================================================================================
447
448 mStatus mDNSPlatformInit( mDNS * const inMDNS )
449 {
450 mStatus err;
451 WSADATA wsaData;
452 int supported;
453
454 dlog( kDebugLevelVerbose, DEBUG_NAME "platform init\n" );
455
456 // Initialize variables.
457
458 memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) );
459 inMDNS->p = &gMDNSPlatformSupport;
460 inMDNS->p->interfaceListChangedSocketRef = kInvalidSocketRef;
461 mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time.
462
463 // Set everything up.
464
465 err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
466 require_noerr( err, exit );
467
468 supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
469 require_action( supported, exit, err = mStatus_UnsupportedErr );
470
471 err = SetupSynchronizationObjects( inMDNS );
472 require_noerr( err, exit );
473
474 err = SetupThread( inMDNS );
475 require_noerr( err, exit );
476
477 // Success!
478
479 mDNSCoreInitComplete( inMDNS, err );
480
481 exit:
482 if( err )
483 {
484 mDNSPlatformClose( inMDNS );
485 }
486 dlog( kDebugLevelVerbose, DEBUG_NAME "platform init done (err=%ld)\n", err );
487 return( err );
488 }
489
490 //===========================================================================================================================
491 // mDNSPlatformClose
492 //===========================================================================================================================
493
494 void mDNSPlatformClose( mDNS * const inMDNS )
495 {
496 mStatus err;
497
498 dlog( kDebugLevelVerbose, DEBUG_NAME "platform close\n" );
499 check( inMDNS );
500
501 // Tear everything down in reverse order to how it was set up.
502
503 err = TearDownThread( inMDNS );
504 check_noerr( err );
505
506 err = TearDownInterfaceList( inMDNS );
507 check_noerr( err );
508
509 err = TearDownSynchronizationObjects( inMDNS );
510 check_noerr( err );
511
512 WSACleanup();
513
514 dlog( kDebugLevelVerbose, DEBUG_NAME "platform close done (err=%ld)\n", err );
515 }
516
517 //===========================================================================================================================
518 // mDNSPlatformSendUDP
519 //===========================================================================================================================
520
521 mStatus
522 mDNSPlatformSendUDP(
523 const mDNS * const inMDNS,
524 const DNSMessage * const inMsg,
525 const mDNSu8 * const inMsgEnd,
526 mDNSInterfaceID inInterfaceID,
527 mDNSIPPort inSrcPort,
528 const mDNSAddr * inDstIP,
529 mDNSIPPort inDstPort )
530 {
531 mStatus err;
532 mDNSInterfaceData * ifd;
533 struct sockaddr_in addr;
534 int n;
535
536 MDNS_UNUSED( inSrcPort );
537 dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP\n" );
538
539 // Check parameters.
540
541 check( inMDNS );
542 check( inMsg );
543 check( inMsgEnd );
544 check( inInterfaceID );
545 check( inDstIP );
546 if( inDstIP->type != mDNSAddrType_IPv4 )
547 {
548 err = mStatus_BadParamErr;
549 goto exit;
550 }
551
552 // Send the packet.
553
554 ifd = (mDNSInterfaceData *) inInterfaceID;
555 check( IsValidSocket( ifd->sock ) );
556
557 addr.sin_family = AF_INET;
558 addr.sin_port = inDstPort.NotAnInteger;
559 addr.sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
560
561 n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
562 n = sendto( ifd->sock, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
563 check_errno( n, errno_compat() );
564
565 ifd->sendErrorCounter += ( n < 0 );
566 ifd->sendMulticastCounter += ( inDstPort.NotAnInteger == MulticastDNSPort.NotAnInteger );
567 ifd->sendUnicastCounter += ( inDstPort.NotAnInteger != MulticastDNSPort.NotAnInteger );
568 err = mStatus_NoError;
569
570 exit:
571 dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP done\n" );
572 return( err );
573 }
574
575 //===========================================================================================================================
576 // mDNSPlatformLock
577 //===========================================================================================================================
578
579 void mDNSPlatformLock( const mDNS * const inMDNS )
580 {
581 EnterCriticalSection( &inMDNS->p->lock );
582 }
583
584 //===========================================================================================================================
585 // mDNSPlatformUnlock
586 //===========================================================================================================================
587
588 void mDNSPlatformUnlock( const mDNS * const inMDNS )
589 {
590 check( inMDNS );
591 check( inMDNS->p );
592 check( inMDNS->p->lockInitialized );
593 check( inMDNS->p->threadID );
594
595 // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task,
596 // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
597
598 if( GetCurrentThreadId() != inMDNS->p->threadID )
599 {
600 BOOL wasSet;
601
602 wasSet = SetEvent( inMDNS->p->wakeupEvent );
603 check( wasSet );
604 }
605 LeaveCriticalSection( &inMDNS->p->lock );
606 }
607
608 //===========================================================================================================================
609 // mDNSPlatformStrLen
610 //===========================================================================================================================
611
612 mDNSu32 mDNSPlatformStrLen( const void *inSrc )
613 {
614 check( inSrc );
615
616 return( (mDNSu32) strlen( (const char *) inSrc ) );
617 }
618
619 //===========================================================================================================================
620 // mDNSPlatformStrCopy
621 //===========================================================================================================================
622
623 void mDNSPlatformStrCopy( const void *inSrc, void *inDst )
624 {
625 check( inSrc );
626 check( inDst );
627
628 strcpy( (char *) inDst, (const char*) inSrc );
629 }
630
631 //===========================================================================================================================
632 // mDNSPlatformMemCopy
633 //===========================================================================================================================
634
635 void mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
636 {
637 check( inSrc );
638 check( inDst );
639
640 memcpy( inDst, inSrc, inSize );
641 }
642
643 //===========================================================================================================================
644 // mDNSPlatformMemSame
645 //===========================================================================================================================
646
647 mDNSBool mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
648 {
649 check( inSrc );
650 check( inDst );
651
652 return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
653 }
654
655 //===========================================================================================================================
656 // mDNSPlatformMemZero
657 //===========================================================================================================================
658
659 void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
660 {
661 check( inDst );
662
663 memset( inDst, 0, inSize );
664 }
665
666 //===========================================================================================================================
667 // mDNSPlatformMemAllocate
668 //===========================================================================================================================
669
670 mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
671 {
672 void * mem;
673
674 check( inSize > 0 );
675
676 mem = malloc( inSize );
677 check( mem );
678
679 return( mem );
680 }
681
682 //===========================================================================================================================
683 // mDNSPlatformMemFree
684 //===========================================================================================================================
685
686 mDNSexport void mDNSPlatformMemFree( void *inMem )
687 {
688 check( inMem );
689
690 free( inMem );
691 }
692
693 //===========================================================================================================================
694 // mDNSPlatformTimeInit
695 //===========================================================================================================================
696
697 mDNSexport mStatus mDNSPlatformTimeInit( mDNSs32 *outTimeNow )
698 {
699 check( outTimeNow );
700
701 // No special setup is required on Windows -- we just use GetTickCount().
702
703 *outTimeNow = mDNSPlatformTimeNow();
704 return( mStatus_NoError );
705 }
706
707 //===========================================================================================================================
708 // mDNSPlatformTimeNow
709 //===========================================================================================================================
710
711 mDNSs32 mDNSPlatformTimeNow( void )
712 {
713 return( (mDNSs32) GetTickCount() );
714 }
715
716 //===========================================================================================================================
717 // mDNSPlatformInterfaceNameToID
718 //===========================================================================================================================
719
720 mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
721 {
722 mStatus err;
723 mDNSInterfaceData * ifd;
724
725 check( inMDNS );
726 check( inMDNS->p );
727 check( inName );
728
729 // Search for an interface with the specified name,
730
731 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
732 {
733 if( strcmp( ifd->name, inName ) == 0 )
734 {
735 break;
736 }
737 }
738 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
739
740 // Success!
741
742 if( outID )
743 {
744 *outID = (mDNSInterfaceID) ifd;
745 }
746 err = mStatus_NoError;
747
748 exit:
749 return( err );
750 }
751
752 //===========================================================================================================================
753 // mDNSPlatformInterfaceIDToInfo
754 //===========================================================================================================================
755
756 mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
757 {
758 mStatus err;
759 mDNSInterfaceData * ifd;
760
761 check( inMDNS );
762 check( inID );
763 check( outInfo );
764
765 // Search for an interface with the specified ID,
766
767 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
768 {
769 if( ifd == (mDNSInterfaceData *) inID )
770 {
771 break;
772 }
773 }
774 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
775
776 // Success!
777
778 outInfo->name = ifd->name;
779 outInfo->ip = ifd->hostSet.ip;
780 err = mStatus_NoError;
781
782 exit:
783 return( err );
784 }
785
786 #if 0
787 #pragma mark -
788 #endif
789
790 //===========================================================================================================================
791 // debugf_
792 //===========================================================================================================================
793
794 #if( MDNS_DEBUGMSGS )
795 void debugf_( const char *inFormat, ... )
796 {
797 char buffer[ 512 ];
798 va_list args;
799 mDNSu32 length;
800
801 va_start( args, inFormat );
802 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
803 va_end( args );
804
805 dlog( kDebugLevelInfo, "%s\n", buffer );
806 }
807 #endif
808
809 //===========================================================================================================================
810 // verbosedebugf_
811 //===========================================================================================================================
812
813 #if( MDNS_DEBUGMSGS > 1 )
814 void verbosedebugf_( const char *inFormat, ... )
815 {
816 char buffer[ 512 ];
817 va_list args;
818 mDNSu32 length;
819
820 va_start( args, inFormat );
821 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
822 va_end( args );
823
824 dlog( kDebugLevelVerbose, "%s\n", buffer );
825 }
826 #endif
827
828 //===========================================================================================================================
829 // LogMsg
830 //===========================================================================================================================
831
832 void LogMsg( const char *inFormat, ... )
833 {
834 char buffer[ 512 ];
835 va_list args;
836 mDNSu32 length;
837
838 va_start( args, inFormat );
839 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
840 va_end( args );
841
842 dlog( kDebugLevelWarning, "%s\n", buffer );
843 }
844
845 #if( MDNS_DEBUGMSGS )
846 //===========================================================================================================================
847 // mDNSPlatformDebugLog
848 //===========================================================================================================================
849
850 mDNSlocal void mDNSPlatformDebugLog( unsigned long inLevel, const char *inFormat, ... )
851 {
852 if( inLevel >= gDebugLevel )
853 {
854 va_list args;
855
856 va_start( args, inFormat );
857 vfprintf( stderr, inFormat, args );
858 fflush( stderr );
859 va_end( args );
860 }
861 }
862
863 //===========================================================================================================================
864 // mDNSPlatformPrintAssert
865 //===========================================================================================================================
866
867 mDNSlocal void
868 mDNSPlatformPrintAssert(
869 const char * inSignature,
870 long inError,
871 const char * inAssertionString,
872 const char * inErrorString,
873 const char * inFileName,
874 unsigned long inLineNumber,
875 const char * inFunction )
876 {
877 char * dataPtr;
878 char buffer[ 512 ];
879 char tempSignatureChar;
880
881 if( !inSignature )
882 {
883 tempSignatureChar = '\0';
884 inSignature = &tempSignatureChar;
885 }
886 dataPtr = buffer;
887 dataPtr += sprintf( dataPtr, "\n" );
888 if( inError != 0 )
889 {
890 dataPtr += sprintf( dataPtr, "[%s] Error: %ld\n", inSignature, inError );
891 }
892 else
893 {
894 dataPtr += sprintf( dataPtr, "[%s] Assertion failed", inSignature );
895 if( inAssertionString )
896 {
897 dataPtr += sprintf( dataPtr, ": %s", inAssertionString );
898 }
899 dataPtr += sprintf( dataPtr, "\n" );
900 }
901 if( inErrorString )
902 {
903 dataPtr += sprintf( dataPtr, "[%s] %s\n", inSignature, inErrorString );
904 }
905 if( inFileName )
906 {
907 dataPtr += sprintf( dataPtr, "[%s] file: \"%s\"\n", inSignature, inFileName );
908 }
909 if( inLineNumber )
910 {
911 dataPtr += sprintf( dataPtr, "[%s] line: %ld\n", inSignature, inLineNumber );
912 }
913 if( inFunction )
914 {
915 dataPtr += sprintf( dataPtr, "[%s] function: \"%s\"\n", inSignature, inFunction );
916 }
917 dataPtr += sprintf( dataPtr, "\n" );
918 fprintf( stderr, "%s", buffer );
919 fflush( stderr );
920 }
921 #endif // MDNS_DEBUGMSGS
922
923 #if 0
924 #pragma mark -
925 #pragma mark == Platform Internals ==
926 #endif
927
928 //===========================================================================================================================
929 // SetupSynchronizationObjects
930 //===========================================================================================================================
931
932 mDNSlocal mStatus SetupSynchronizationObjects( mDNS * const inMDNS )
933 {
934 mStatus err;
935
936 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up synchronization objects\n" );
937
938 InitializeCriticalSection( &inMDNS->p->lock );
939 inMDNS->p->lockInitialized = mDNStrue;
940
941 inMDNS->p->cancelEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
942 require_action( inMDNS->p->cancelEvent, exit, err = mStatus_NoMemoryErr );
943
944 inMDNS->p->quitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
945 require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
946
947 inMDNS->p->interfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
948 require_action( inMDNS->p->interfaceListChangedEvent, exit, err = mStatus_NoMemoryErr );
949
950 inMDNS->p->wakeupEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
951 require_action( inMDNS->p->wakeupEvent, exit, err = mStatus_NoMemoryErr );
952
953 err = mStatus_NoError;
954
955 exit:
956 if( err )
957 {
958 TearDownSynchronizationObjects( inMDNS );
959 }
960 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up synchronization objects done (err=%ld)\n", err );
961 return( err );
962 }
963
964 //===========================================================================================================================
965 // TearDownSynchronizationObjects
966 //===========================================================================================================================
967
968 mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS )
969 {
970 mStatus err;
971
972 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down synchronization objects\n" );
973
974 if( inMDNS->p->quitEvent )
975 {
976 CloseHandle( inMDNS->p->quitEvent );
977 inMDNS->p->quitEvent = 0;
978 }
979 if( inMDNS->p->cancelEvent )
980 {
981 CloseHandle( inMDNS->p->cancelEvent );
982 inMDNS->p->cancelEvent = 0;
983 }
984 if( inMDNS->p->interfaceListChangedEvent )
985 {
986 CloseHandle( inMDNS->p->interfaceListChangedEvent );
987 inMDNS->p->interfaceListChangedEvent = 0;
988 }
989 if( inMDNS->p->wakeupEvent )
990 {
991 CloseHandle( inMDNS->p->wakeupEvent );
992 inMDNS->p->wakeupEvent = 0;
993 }
994 if( inMDNS->p->lockInitialized )
995 {
996 DeleteCriticalSection( &inMDNS->p->lock );
997 inMDNS->p->lockInitialized = mDNSfalse;
998 }
999 err = mStatus_NoError;
1000
1001 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down synchronization objects done (err=%ld)\n", err );
1002 return( err );
1003 }
1004
1005 //===========================================================================================================================
1006 // SetupName
1007 //===========================================================================================================================
1008
1009 mDNSlocal mStatus SetupName( mDNS * const inMDNS )
1010 {
1011 mStatus err;
1012 char tempString[ 256 ];
1013
1014 check( inMDNS );
1015
1016 // Get the name of this machine.
1017
1018 tempString[ 0 ] = '\0';
1019 err = gethostname( tempString, sizeof( tempString ) - 1 );
1020 check_errno( err, errno_compat() );
1021 if( err || ( tempString[ 0 ] == '\0' ) )
1022 {
1023 // Invalidate name so fall back to a default name.
1024
1025 strcpy( tempString, kMDNSDefaultName );
1026 }
1027 tempString[ sizeof( tempString ) - 1 ] = '\0';
1028
1029 // Set up the host name with mDNS.
1030
1031 inMDNS->nicelabel.c[ 0 ] = (mDNSu8) strlen( tempString );
1032 memcpy( &inMDNS->nicelabel.c[ 1 ], tempString, inMDNS->nicelabel.c[ 0 ] );
1033 ConvertUTF8PstringToRFC1034HostLabel( inMDNS->nicelabel.c, &inMDNS->hostlabel );
1034 if( inMDNS->hostlabel.c[ 0 ] == 0 )
1035 {
1036 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
1037
1038 MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
1039 }
1040 check( inMDNS->nicelabel.c[ 0 ] != 0 );
1041 check( inMDNS->hostlabel.c[ 0 ] != 0 );
1042
1043 mDNS_GenerateFQDN( inMDNS );
1044
1045 dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
1046 dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
1047 return( err );
1048 }
1049
1050 //===========================================================================================================================
1051 // SetupInterfaceList
1052 //===========================================================================================================================
1053
1054 mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
1055 {
1056 mStatus err;
1057 mDNSInterfaceData ** next;
1058 mDNSInterfaceData * ifd;
1059 struct ifaddrs * addrs;
1060 struct ifaddrs * p;
1061 u_int flagMask;
1062 u_int flagTest;
1063
1064 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list\n" );
1065 check( inMDNS );
1066 check( inMDNS->p );
1067
1068 addrs = NULL;
1069
1070 // Tear down any existing interfaces that may be set up.
1071
1072 TearDownInterfaceList( inMDNS );
1073
1074 // Set up the name of this machine.
1075
1076 err = SetupName( inMDNS );
1077 check_noerr( err );
1078
1079 // Set up the interface list change notification.
1080
1081 err = SetupNotifications( inMDNS );
1082 check_noerr( err );
1083
1084 // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
1085
1086 flagMask = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTTOPOINT;
1087 flagTest = IFF_UP | IFF_MULTICAST;
1088
1089 next = &inMDNS->p->interfaceList;
1090
1091 err = getifaddrs( &addrs );
1092 require_noerr( err, exit );
1093
1094 for( p = addrs; p; p = p->ifa_next )
1095 {
1096 if( ( p->ifa_flags & flagMask ) == flagTest )
1097 {
1098 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) ) // $$$ TO DO: Update for IPv6.
1099 {
1100 continue;
1101 }
1102
1103 err = SetupInterface( inMDNS, (struct sockaddr_in *) p->ifa_addr, &ifd );
1104 require_noerr( err, exit );
1105
1106 strcpy( ifd->name, p->ifa_name );
1107
1108 *next = ifd;
1109 next = &ifd->next;
1110 ++inMDNS->p->interfaceCount;
1111 }
1112 }
1113
1114 exit:
1115 if( err )
1116 {
1117 TearDownInterfaceList( inMDNS );
1118 }
1119 if( addrs )
1120 {
1121 freeifaddrs( addrs );
1122 }
1123 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list done (err=%ld)\n", err );
1124 return( err );
1125 }
1126
1127 //===========================================================================================================================
1128 // TearDownInterfaceList
1129 //===========================================================================================================================
1130
1131 mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS )
1132 {
1133 mStatus err;
1134 mDNSInterfaceData * ifd;
1135
1136 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list\n" );
1137 check( inMDNS );
1138 check( inMDNS->p );
1139
1140 // Tear down interface list change notifications.
1141
1142 err = TearDownNotifications( inMDNS );
1143 check_noerr( err );
1144
1145 // Tear down all the interfaces.
1146
1147 while( inMDNS->p->interfaceList )
1148 {
1149 ifd = inMDNS->p->interfaceList;
1150 inMDNS->p->interfaceList = ifd->next;
1151
1152 TearDownInterface( inMDNS, ifd );
1153 }
1154 inMDNS->p->interfaceCount = 0;
1155
1156 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list done\n" );
1157 return( mStatus_NoError );
1158 }
1159
1160 //===========================================================================================================================
1161 // SetupInterface
1162 //===========================================================================================================================
1163
1164 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct sockaddr_in *inAddress, mDNSInterfaceData **outIFD )
1165 {
1166 mStatus err;
1167 mDNSInterfaceData * ifd;
1168 SocketRef socketRef;
1169
1170 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface\n" );
1171 check( inMDNS );
1172 check( inMDNS->p );
1173 check( inAddress );
1174 check( outIFD );
1175
1176 // Allocate memory for the info item.
1177
1178 ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
1179 require_action( ifd, exit, err = mStatus_NoMemoryErr );
1180 ifd->sock = kInvalidSocketRef;
1181
1182 // Set up a multicast DNS (port 5353) socket for this interface.
1183
1184 err = SetupSocket( inMDNS, inAddress, &socketRef );
1185 require_noerr( err, exit );
1186 ifd->sock = socketRef;
1187
1188 // Set up the read pending event and associate it so we can block until data is available for this socket.
1189
1190 ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1191 require_action( ifd->readPendingEvent, exit, err = mStatus_NoMemoryErr );
1192
1193 err = WSAEventSelect( ifd->sock, ifd->readPendingEvent, FD_READ );
1194 require_noerr( err, exit );
1195
1196 // Register this interface with mDNS.
1197
1198 ifd->hostSet.InterfaceID = (mDNSInterfaceID) ifd;
1199 ifd->hostSet.ip.type = mDNSAddrType_IPv4;
1200 ifd->hostSet.ip.ip.v4.NotAnInteger = inAddress->sin_addr.s_addr;
1201 ifd->hostSet.Advertise = inMDNS->AdvertiseLocalAddresses;
1202
1203 err = mDNS_RegisterInterface( inMDNS, &ifd->hostSet );
1204 require_noerr( err, exit );
1205 ifd->hostRegistered = mDNStrue;
1206
1207 dlog( kDebugLevelInfo, DEBUG_NAME "Registered IP address: %u.%u.%u.%u\n",
1208 ifd->hostSet.ip.ip.v4.b[ 0 ],
1209 ifd->hostSet.ip.ip.v4.b[ 1 ],
1210 ifd->hostSet.ip.ip.v4.b[ 2 ],
1211 ifd->hostSet.ip.ip.v4.b[ 3 ] );
1212
1213 // Success!
1214
1215 *outIFD = ifd;
1216 ifd = NULL;
1217
1218 exit:
1219 if( ifd )
1220 {
1221 TearDownInterface( inMDNS, ifd );
1222 }
1223 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface done (err=%ld)\n", err );
1224 return( err );
1225 }
1226
1227 //===========================================================================================================================
1228 // TearDownInterface
1229 //===========================================================================================================================
1230
1231 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
1232 {
1233 SocketRef socketRef;
1234
1235 check( inMDNS );
1236 check( inIFD );
1237
1238 // Deregister this interface with mDNS.
1239
1240 dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering IP address: %u.%u.%u.%u\n",
1241 inIFD->hostSet.ip.ip.v4.b[ 0 ],
1242 inIFD->hostSet.ip.ip.v4.b[ 1 ],
1243 inIFD->hostSet.ip.ip.v4.b[ 2 ],
1244 inIFD->hostSet.ip.ip.v4.b[ 3 ] );
1245
1246 if( inIFD->hostRegistered )
1247 {
1248 inIFD->hostRegistered = mDNSfalse;
1249 mDNS_DeregisterInterface( inMDNS, &inIFD->hostSet );
1250 }
1251
1252 // Tear down the multicast socket.
1253
1254 if( inIFD->readPendingEvent )
1255 {
1256 CloseHandle( inIFD->readPendingEvent );
1257 inIFD->readPendingEvent = 0;
1258 }
1259
1260 socketRef = inIFD->sock;
1261 inIFD->sock = kInvalidSocketRef;
1262 if( IsValidSocket( socketRef ) )
1263 {
1264 dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down socket %d\n", socketRef );
1265 close_compat( socketRef );
1266 }
1267
1268 // Free the memory used by the interface info.
1269
1270 free( inIFD );
1271 return( mStatus_NoError );
1272 }
1273
1274 //===========================================================================================================================
1275 // SetupSocket
1276 //===========================================================================================================================
1277
1278 mDNSlocal mStatus
1279 SetupSocket(
1280 mDNS * const inMDNS,
1281 const struct sockaddr_in * inAddress,
1282 SocketRef * outSocketRef )
1283 {
1284 mStatus err;
1285 SocketRef socketRef;
1286 int option;
1287 struct ip_mreq mreq;
1288 struct sockaddr_in addr;
1289 mDNSv4Addr ip;
1290
1291 MDNS_UNUSED( inMDNS );
1292
1293 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done\n" );
1294 check( inMDNS );
1295 check( outSocketRef );
1296
1297 // Set up a UDP socket.
1298
1299 socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1300 require_action( IsValidSocket( socketRef ), exit, err = mStatus_NoMemoryErr );
1301
1302 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets.
1303
1304 option = 1;
1305 err = setsockopt( socketRef, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
1306 check_errno( err, errno_compat() );
1307
1308 // Bind to the mutlicast DNS port 5353.
1309
1310 ip.NotAnInteger = inAddress->sin_addr.s_addr;
1311 memset( &addr, 0, sizeof( addr ) );
1312 addr.sin_family = AF_INET;
1313 addr.sin_port = MulticastDNSPort.NotAnInteger;
1314 addr.sin_addr.s_addr = ip.NotAnInteger;
1315 err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
1316 check_errno( err, errno_compat() );
1317
1318 // Join the all-DNS multicast group so we receive Multicast DNS packets.
1319
1320 mreq.imr_multiaddr.s_addr = AllDNSLinkGroup.NotAnInteger;
1321 mreq.imr_interface.s_addr = ip.NotAnInteger;
1322 err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) );
1323 check_errno( err, errno_compat() );
1324
1325 // Direct multicast packets to the specified interface.
1326
1327 addr.sin_addr.s_addr = ip.NotAnInteger;
1328 err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addr.sin_addr, sizeof( addr.sin_addr ) );
1329 check_errno( err, errno_compat() );
1330
1331 // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
1332
1333 option = 255;
1334 err = setsockopt( socketRef, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
1335 check_errno( err, errno_compat() );
1336
1337 // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
1338
1339 option = 255;
1340 err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
1341 check_errno( err, errno_compat() );
1342
1343 // Success!
1344
1345 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done (%u.%u.%u.%u, %d)\n",
1346 ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], socketRef );
1347
1348 *outSocketRef = socketRef;
1349 socketRef = kInvalidSocketRef;
1350 err = mStatus_NoError;
1351
1352 exit:
1353 if( IsValidSocket( socketRef ) )
1354 {
1355 close_compat( socketRef );
1356 }
1357 return( err );
1358 }
1359
1360 //===========================================================================================================================
1361 // SetupNotifications
1362 //===========================================================================================================================
1363
1364 mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS )
1365 {
1366 mStatus err;
1367 SocketRef socketRef;
1368 unsigned long param;
1369 int inBuffer;
1370 int outBuffer;
1371 DWORD outSize;
1372
1373 // Register to listen for address list changes.
1374
1375 socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1376 require_action( IsValidSocket( socketRef ), exit, err = mStatus_NoMemoryErr );
1377 inMDNS->p->interfaceListChangedSocketRef = socketRef;
1378
1379 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1380 // when a change to the interface list is detected.
1381
1382 param = 1;
1383 err = ioctlsocket( socketRef, FIONBIO, &param );
1384 require_errno( err, errno_compat(), exit );
1385
1386 inBuffer = 0;
1387 outBuffer = 0;
1388 err = WSAIoctl( socketRef, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
1389 if( err < 0 )
1390 {
1391 check( errno_compat() == WSAEWOULDBLOCK );
1392 }
1393
1394 err = WSAEventSelect( socketRef, inMDNS->p->interfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
1395 require_errno( err, errno_compat(), exit );
1396
1397 exit:
1398 if( err )
1399 {
1400 TearDownNotifications( inMDNS );
1401 }
1402 return( err );
1403 }
1404
1405 //===========================================================================================================================
1406 // TearDownNotifications
1407 //===========================================================================================================================
1408
1409 mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS )
1410 {
1411 SocketRef socketRef;
1412
1413 socketRef = inMDNS->p->interfaceListChangedSocketRef;
1414 inMDNS->p->interfaceListChangedSocketRef = kInvalidSocketRef;
1415 if( IsValidSocket( socketRef ) )
1416 {
1417 close_compat( socketRef );
1418 }
1419 return( mStatus_NoError );
1420 }
1421
1422 #if 0
1423 #pragma mark -
1424 #endif
1425
1426 //===========================================================================================================================
1427 // SetupThread
1428 //===========================================================================================================================
1429
1430 mDNSlocal mStatus SetupThread( mDNS * const inMDNS )
1431 {
1432 mStatus err;
1433 HANDLE threadHandle;
1434 unsigned threadID;
1435 DWORD result;
1436
1437 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread\n" );
1438
1439 // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
1440 // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
1441
1442 inMDNS->p->initEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1443 require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr );
1444 inMDNS->p->initStatus = mStatus_Invalid;
1445
1446 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1447 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1448
1449 threadHandle = (HANDLE) _beginthreadex( NULL, 0, ProcessingThread, inMDNS, 0, &threadID );
1450 require_action( threadHandle, exit, err = mStatus_NoMemoryErr );
1451
1452 result = WaitForSingleObject( inMDNS->p->initEvent, INFINITE );
1453 require_action( result == WAIT_OBJECT_0, exit, err = mStatus_UnknownErr );
1454 err = inMDNS->p->initStatus;
1455 require_noerr( err, exit );
1456
1457 exit:
1458 if( inMDNS->p->initEvent )
1459 {
1460 CloseHandle( inMDNS->p->initEvent );
1461 inMDNS->p->initEvent = 0;
1462 }
1463 dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread done (err=%ld)\n", err );
1464 return( err );
1465 }
1466
1467 //===========================================================================================================================
1468 // TearDownThread
1469 //===========================================================================================================================
1470
1471 mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS )
1472 {
1473 DWORD result;
1474
1475 // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did
1476 // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
1477
1478 if( inMDNS->p->cancelEvent )
1479 {
1480 BOOL wasSet;
1481
1482 wasSet = SetEvent( inMDNS->p->cancelEvent );
1483 check( wasSet );
1484
1485 if( inMDNS->p->quitEvent )
1486 {
1487 result = WaitForSingleObject( inMDNS->p->quitEvent, 5 * 1000 );
1488 check( result == WAIT_OBJECT_0 );
1489 }
1490 }
1491 return( mStatus_NoError );
1492 }
1493
1494 //===========================================================================================================================
1495 // ProcessingThread
1496 //===========================================================================================================================
1497
1498 mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
1499 {
1500 mDNS * m;
1501 int done;
1502 mStatus err;
1503 HANDLE * waitList;
1504 int waitListCount;
1505 DWORD result;
1506 BOOL wasSet;
1507
1508 check( inParam );
1509
1510 m = (mDNS *) inParam;
1511 err = ProcessingThreadInitialize( m );
1512 require_noerr( err, exit );
1513
1514 done = 0;
1515 while( !done )
1516 {
1517 // Set up the list of objects we'll be waiting on.
1518
1519 waitList = NULL;
1520 waitListCount = 0;
1521 err = ProcessingThreadSetupWaitList( m, &waitList, &waitListCount );
1522 require_noerr( err, exit );
1523
1524 // Main processing loop.
1525
1526 for( ;; )
1527 {
1528 // Give the mDNS core a chance to do its work and determine next event time.
1529
1530 mDNSs32 interval = mDNS_Execute(m) - mDNSPlatformTimeNow();
1531 if (interval < 0) interval = 0;
1532 else if (interval > (0x7FFFFFFF / 1000)) interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
1533 else interval = (interval * 1000) / mDNSPlatformOneSecond;
1534
1535 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1536
1537 result = WaitForMultipleObjects( (DWORD) waitListCount, waitList, FALSE, (DWORD) interval );
1538 if( result == WAIT_TIMEOUT )
1539 {
1540 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1541
1542 dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
1543 continue;
1544 }
1545 else if( result == kWaitListCancelEvent )
1546 {
1547 // Cancel event. Set the done flag and break to exit.
1548
1549 dlog( kDebugLevelVerbose, DEBUG_NAME "canceling...\n" );
1550 done = 1;
1551 break;
1552 }
1553 else if( result == kWaitListInterfaceListChangedEvent )
1554 {
1555 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1556
1557 ProcessingThreadInterfaceListChanged( m );
1558 break;
1559 }
1560 else if( result == kWaitListWakeupEvent )
1561 {
1562 // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
1563
1564 dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup\n" );
1565 continue;
1566 }
1567 else
1568 {
1569 int waitItemIndex;
1570
1571 // Socket data available event. Determine which socket and process the packet.
1572
1573 waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
1574 dlog( kDebugLevelChatty, DEBUG_NAME "socket data available on socket index %d\n", waitItemIndex );
1575 check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
1576 if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
1577 {
1578 HANDLE signaledObject;
1579 int n;
1580 mDNSInterfaceData * ifd;
1581
1582 signaledObject = waitList[ waitItemIndex ];
1583
1584 n = 0;
1585 for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
1586 {
1587 if( ifd->readPendingEvent == signaledObject )
1588 {
1589 ProcessingThreadProcessPacket( m, ifd, ifd->sock );
1590 ++n;
1591 }
1592 }
1593 check( n > 0 );
1594 }
1595 else
1596 {
1597 // Unexpected wait result.
1598
1599 dlog( kDebugLevelAllowedError, DEBUG_NAME "unexpected wait result (result=0x%08X)\n", result );
1600 }
1601 }
1602 }
1603
1604 // Release the wait list.
1605
1606 if( waitList )
1607 {
1608 free( waitList );
1609 waitList = NULL;
1610 waitListCount = 0;
1611 }
1612 }
1613
1614 // Signal the quit event to indicate that the thread is finished.
1615
1616 exit:
1617 wasSet = SetEvent( m->p->quitEvent );
1618 check( wasSet );
1619
1620 // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
1621 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1622
1623 _endthreadex( 0 );
1624 return( 0 );
1625 }
1626
1627 //===========================================================================================================================
1628 // ProcessingThreadInitialize
1629 //===========================================================================================================================
1630
1631 mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
1632 {
1633 mStatus err;
1634 BOOL wasSet;
1635
1636 inMDNS->p->threadID = GetCurrentThreadId();
1637
1638 err = SetupInterfaceList( inMDNS );
1639 require_noerr( err, exit );
1640
1641 exit:
1642 if( err )
1643 {
1644 TearDownInterfaceList( inMDNS );
1645 }
1646 inMDNS->p->initStatus = err;
1647 wasSet = SetEvent( inMDNS->p->initEvent );
1648 check( wasSet );
1649
1650 return( err );
1651 }
1652
1653 //===========================================================================================================================
1654 // ProcessingThreadSetupWaitList
1655 //===========================================================================================================================
1656
1657 mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
1658 {
1659 mStatus err;
1660 int waitListCount;
1661 HANDLE * waitList;
1662 HANDLE * waitItemPtr;
1663 mDNSInterfaceData * ifd;
1664
1665 dlog( kDebugLevelVerbose, DEBUG_NAME "thread setting up wait list\n" );
1666 check( inMDNS );
1667 check( inMDNS->p );
1668 check( outWaitList );
1669 check( outWaitListCount );
1670
1671 // Allocate an array to hold all the objects to wait on.
1672
1673 waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount;
1674 waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
1675 require_action( waitList, exit, err = mStatus_NoMemoryErr );
1676 waitItemPtr = waitList;
1677
1678 // Add the fixed wait items to the beginning of the list.
1679
1680 *waitItemPtr++ = inMDNS->p->cancelEvent;
1681 *waitItemPtr++ = inMDNS->p->interfaceListChangedEvent;
1682 *waitItemPtr++ = inMDNS->p->wakeupEvent;
1683
1684 // Append all the dynamic wait items to the list.
1685
1686 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
1687 {
1688 *waitItemPtr++ = ifd->readPendingEvent;
1689 }
1690
1691 *outWaitList = waitList;
1692 *outWaitListCount = waitListCount;
1693 waitList = NULL;
1694 err = mStatus_NoError;
1695
1696 exit:
1697 if( waitList )
1698 {
1699 free( waitList );
1700 }
1701 dlog( kDebugLevelVerbose, DEBUG_NAME "thread setting up wait list done (err=%ld)\n", err );
1702 return( err );
1703 }
1704
1705 //===========================================================================================================================
1706 // ProcessingThreadProcessPacket
1707 //===========================================================================================================================
1708
1709 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSocketRef )
1710 {
1711 int n;
1712 DNSMessage packet;
1713 struct sockaddr_in addr;
1714 int addrSize;
1715 mDNSu8 * packetEndPtr;
1716 mDNSAddr srcAddr;
1717 mDNSIPPort srcPort;
1718 mDNSAddr dstAddr;
1719 mDNSIPPort dstPort;
1720
1721 // Receive the packet.
1722
1723 addrSize = sizeof( addr );
1724 n = recvfrom( inSocketRef, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
1725 check( n >= 0 );
1726 if( n >= 0 )
1727 {
1728 // Set up the src/dst/interface info.
1729
1730 srcAddr.type = mDNSAddrType_IPv4;
1731 srcAddr.ip.v4.NotAnInteger = addr.sin_addr.s_addr;
1732 srcPort.NotAnInteger = addr.sin_port;
1733 dstAddr.type = mDNSAddrType_IPv4;
1734 dstAddr.ip.v4 = AllDNSLinkGroup;
1735 dstPort = MulticastDNSPort;
1736
1737 dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
1738 dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", n );
1739 dlog( kDebugLevelChatty, DEBUG_NAME " src = %u.%u.%u.%u:%u\n",
1740 srcAddr.ip.v4.b[ 0 ], srcAddr.ip.v4.b[ 1 ], srcAddr.ip.v4.b[ 2 ], srcAddr.ip.v4.b[ 3 ],
1741 ntohs( srcPort.NotAnInteger ) );
1742 dlog( kDebugLevelChatty, DEBUG_NAME " dst = %u.%u.%u.%u:%u\n",
1743 dstAddr.ip.v4.b[ 0 ], dstAddr.ip.v4.b[ 1 ], dstAddr.ip.v4.b[ 2 ], dstAddr.ip.v4.b[ 3 ],
1744 ntohs( dstPort.NotAnInteger ) );
1745 dlog( kDebugLevelChatty, DEBUG_NAME " interface = %u.%u.%u.%u\n",
1746 inIFD->hostSet.ip.ip.v4.b[ 0 ], inIFD->hostSet.ip.ip.v4.b[ 1 ],
1747 inIFD->hostSet.ip.ip.v4.b[ 2 ], inIFD->hostSet.ip.ip.v4.b[ 3 ] );
1748
1749 dlog( kDebugLevelChatty, DEBUG_NAME "--\n" );
1750
1751 // Dispatch the packet to mDNS.
1752
1753 packetEndPtr = ( (mDNSu8 *) &packet ) + n;
1754 mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->hostSet.InterfaceID, 255 );
1755 }
1756
1757 // Update counters.
1758
1759 inIFD->recvCounter += 1;
1760 inIFD->recvErrorCounter += ( n < 0 );
1761 }
1762
1763 //===========================================================================================================================
1764 // ProcessingThreadInterfaceListChanged
1765 //===========================================================================================================================
1766
1767 mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
1768 {
1769 mStatus err;
1770
1771 dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed event\n" );
1772 check( inMDNS );
1773
1774 mDNSPlatformLock( inMDNS );
1775
1776 // Tear down the existing interfaces and set up new ones using the new IP info.
1777
1778 err = TearDownInterfaceList( inMDNS );
1779 check_noerr( err );
1780
1781 err = SetupInterfaceList( inMDNS );
1782 check_noerr( err );
1783
1784 mDNSPlatformUnlock( inMDNS );
1785
1786 // Inform clients of the change.
1787
1788 if( inMDNS->MainCallback )
1789 {
1790 inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged );
1791 }
1792
1793 // Force mDNS to update.
1794
1795 mDNSCoreMachineSleep( inMDNS, mDNSfalse );
1796 }
1797
1798 #if 0
1799 #pragma mark -
1800 #pragma mark == Utilities ==
1801 #endif
1802
1803 #if( defined( _WIN32_WCE ) )
1804 //===========================================================================================================================
1805 // getifaddrs
1806 //===========================================================================================================================
1807
1808 int getifaddrs( struct ifaddrs **outAddrs )
1809 {
1810 int err;
1811 SocketRef sock;
1812 DWORD size;
1813 void * buffer;
1814 SOCKET_ADDRESS_LIST * addressList;
1815 struct ifaddrs * head;
1816 struct ifaddrs ** next;
1817 struct ifaddrs * ifa;
1818 int n;
1819 int i;
1820
1821 sock = kInvalidSocketRef;
1822 buffer = NULL;
1823 head = NULL;
1824 next = &head;
1825
1826 // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
1827
1828 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1829 require_action( IsValidSocket( sock ), exit, err = mStatus_NoMemoryErr );
1830
1831 // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to
1832 // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
1833 //
1834 // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
1835
1836 size = 0;
1837 WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL );
1838 require_action( size > 0, exit, err = -1 );
1839 size *= 2;
1840
1841 buffer = calloc( 1, size );
1842 require_action( buffer, exit, err = -1 );
1843
1844 // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
1845
1846 err = WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, size, &size, NULL, NULL );
1847 require_noerr( err, exit );
1848 addressList = (SOCKET_ADDRESS_LIST *) buffer;
1849
1850 // Process the raw interface list and build a linked list of interfaces.
1851 //
1852 // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
1853
1854 n = addressList->iAddressCount;
1855 if( n == 0 )
1856 {
1857 n = 1;
1858 }
1859 for( i = 0; i < n; ++i )
1860 {
1861 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
1862 require_action( ifa, exit, err = WSAENOBUFS );
1863
1864 *next = ifa;
1865 next = &ifa->ifa_next;
1866
1867 // Fetch the name. $$$ TO DO: Get the real name of the interface.
1868
1869 ifa->ifa_name = (char *) malloc( 16 );
1870 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
1871 sprintf( ifa->ifa_name, "%d", i + 1 );
1872
1873 // Fetch flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
1874
1875 ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
1876
1877 // Fetch addresses.
1878
1879 switch( addressList->Address[ i ].lpSockaddr->sa_family )
1880 {
1881 case AF_INET:
1882 {
1883 struct sockaddr_in * sinptr4;
1884
1885 sinptr4 = (struct sockaddr_in *) addressList->Address[ i ].lpSockaddr;
1886 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
1887 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
1888 memcpy( ifa->ifa_addr, sinptr4, sizeof( *sinptr4 ) );
1889 break;
1890 }
1891
1892 default:
1893 break;
1894 }
1895 }
1896
1897 // Success!
1898
1899 if( outAddrs )
1900 {
1901 *outAddrs = head;
1902 head = NULL;
1903 }
1904 err = 0;
1905
1906 exit:
1907 if( head )
1908 {
1909 freeifaddrs( head );
1910 }
1911 if( buffer )
1912 {
1913 free( buffer );
1914 }
1915 if( sock != INVALID_SOCKET )
1916 {
1917 closesocket( sock );
1918 }
1919 return( err );
1920 }
1921 #endif // defined( _WIN32_WCE ) )
1922
1923 #if( !defined( _WIN32_WCE ) )
1924 //===========================================================================================================================
1925 // getifaddrs
1926 //===========================================================================================================================
1927
1928 int getifaddrs( struct ifaddrs **outAddrs )
1929 {
1930 int err;
1931 SOCKET sock;
1932 DWORD size;
1933 DWORD actualSize;
1934 INTERFACE_INFO * buffer;
1935 INTERFACE_INFO * tempBuffer;
1936 INTERFACE_INFO * ifInfo;
1937 int n;
1938 int i;
1939 struct ifaddrs * head;
1940 struct ifaddrs ** next;
1941 struct ifaddrs * ifa;
1942 struct sockaddr_in * sinptr4;
1943 struct sockaddr_in6_old * sinptr6;
1944 struct sockaddr * sa;
1945
1946 sock = INVALID_SOCKET;
1947 buffer = NULL;
1948 head = NULL;
1949 next = &head;
1950
1951 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
1952 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
1953 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
1954
1955 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
1956 require_action( sock != INVALID_SOCKET, exit, err = WSAEMFILE );
1957
1958 n = 0;
1959 size = 16 * sizeof( INTERFACE_INFO );
1960 for( ;; )
1961 {
1962 tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
1963 require_action( tempBuffer, exit, err = WSAENOBUFS );
1964 buffer = tempBuffer;
1965
1966 err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
1967 if( err == 0 )
1968 {
1969 break;
1970 }
1971
1972 ++n;
1973 require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
1974
1975 size += ( 16 * sizeof( INTERFACE_INFO ) );
1976 }
1977 check( actualSize <= size );
1978 check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
1979 n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
1980
1981 // Process the raw interface list and build a linked list of interfaces.
1982
1983 for( i = 0; i < n; ++i )
1984 {
1985 ifInfo = &buffer[ i ];
1986
1987 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
1988 require_action( ifa, exit, err = WSAENOBUFS );
1989
1990 *next = ifa;
1991 next = &ifa->ifa_next;
1992
1993 // Fetch the name. $$$ TO DO: Get the real name of the interface.
1994
1995 ifa->ifa_name = (char *) malloc( 16 );
1996 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
1997 sprintf( ifa->ifa_name, "%d", i + 1 );
1998
1999 // Fetch interface flags.
2000
2001 ifa->ifa_flags = (u_int) ifInfo->iiFlags;
2002
2003 // Fetch addresses.
2004
2005 switch( ifInfo->iiAddress.Address.sa_family )
2006 {
2007 case AF_INET:
2008 sinptr4 = &ifInfo->iiAddress.AddressIn;
2009 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
2010 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
2011 memcpy( ifa->ifa_addr, sinptr4, sizeof( *sinptr4 ) );
2012
2013 if( ifInfo->iiNetmask.Address.sa_family == AF_INET )
2014 {
2015 sinptr4 = &ifInfo->iiNetmask.AddressIn;
2016 ifa->ifa_netmask = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
2017 require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
2018 memcpy( ifa->ifa_netmask, sinptr4, sizeof( *sinptr4 ) );
2019 }
2020
2021 if( ifInfo->iiBroadcastAddress.Address.sa_family == AF_INET )
2022 {
2023 sinptr4 = &ifInfo->iiBroadcastAddress.AddressIn;
2024 ifa->ifa_broadaddr = (struct sockaddr *) calloc( 1, sizeof( *sinptr4 ) );
2025 require_action( ifa->ifa_broadaddr, exit, err = WSAENOBUFS );
2026 memcpy( ifa->ifa_broadaddr, sinptr4, sizeof( *sinptr4 ) );
2027 }
2028 break;
2029
2030 case AF_INET6:
2031 sinptr6 = &ifInfo->iiAddress.AddressIn6;
2032 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sinptr6 ) );
2033 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
2034 memcpy( ifa->ifa_addr, sinptr6, sizeof( *sinptr6 ) );
2035 break;
2036
2037 default:
2038 sa = &ifInfo->iiAddress.Address;
2039 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa ) );
2040 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
2041 memcpy( ifa->ifa_addr, sa, sizeof( *sa ) );
2042 break;
2043 }
2044 }
2045
2046 // Success!
2047
2048 if( outAddrs )
2049 {
2050 *outAddrs = head;
2051 head = NULL;
2052 }
2053 err = 0;
2054
2055 exit:
2056 if( head )
2057 {
2058 freeifaddrs( head );
2059 }
2060 if( buffer )
2061 {
2062 free( buffer );
2063 }
2064 if( sock != INVALID_SOCKET )
2065 {
2066 closesocket( sock );
2067 }
2068 return( err );
2069 }
2070 #endif // !defined( _WIN32_WCE ) )
2071
2072 //===========================================================================================================================
2073 // freeifaddrs
2074 //===========================================================================================================================
2075
2076 void freeifaddrs( struct ifaddrs *inAddrs )
2077 {
2078 struct ifaddrs * p;
2079 struct ifaddrs * q;
2080
2081 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
2082
2083 for( p = inAddrs; p; p = q )
2084 {
2085 q = p->ifa_next;
2086
2087 if( p->ifa_name )
2088 {
2089 free( p->ifa_name );
2090 p->ifa_name = NULL;
2091 }
2092 if( p->ifa_addr )
2093 {
2094 free( p->ifa_addr );
2095 p->ifa_addr = NULL;
2096 }
2097 if( p->ifa_netmask )
2098 {
2099 free( p->ifa_netmask );
2100 p->ifa_netmask = NULL;
2101 }
2102 if( p->ifa_broadaddr )
2103 {
2104 free( p->ifa_broadaddr );
2105 p->ifa_broadaddr = NULL;
2106 }
2107 if( p->ifa_dstaddr )
2108 {
2109 free( p->ifa_dstaddr );
2110 p->ifa_dstaddr = NULL;
2111 }
2112 if( p->ifa_data )
2113 {
2114 free( p->ifa_data );
2115 p->ifa_data = NULL;
2116 }
2117 free( p );
2118 }
2119 }
2120
2121 #if( !defined( _WIN32_WCE ) )
2122 //===========================================================================================================================
2123 // sock_pton
2124 //===========================================================================================================================
2125
2126 int sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize )
2127 {
2128 int err;
2129 int size;
2130
2131 if( inAddrSize == 0 )
2132 {
2133 if( inFamily == AF_INET )
2134 {
2135 inAddrSize = sizeof( struct sockaddr_in );
2136 }
2137 else if( inFamily == AF_INET6 )
2138 {
2139 inAddrSize = sizeof( struct sockaddr_in6 );
2140 }
2141 else
2142 {
2143 err = WSAEAFNOSUPPORT;
2144 goto exit;
2145 }
2146 }
2147 size = (int) inAddrSize;
2148
2149 err = WSAStringToAddressA( (char *) inString, inFamily, NULL, (LPSOCKADDR) outAddr, &size );
2150 if( err != 0 ) goto exit;
2151
2152 if( outAddrSize )
2153 {
2154 *outAddrSize = (size_t) size;
2155 }
2156
2157 exit:
2158 return( err );
2159 }
2160
2161 //===========================================================================================================================
2162 // sock_ntop
2163 //===========================================================================================================================
2164
2165 char * sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize )
2166 {
2167 DWORD size;
2168 int err;
2169 DWORD stringSize;
2170
2171 if( inAddrSize == 0 )
2172 {
2173 const struct sockaddr * addr;
2174
2175 addr = (const struct sockaddr *) inAddr;
2176 if( addr->sa_family == AF_INET )
2177 {
2178 size = sizeof( struct sockaddr_in );
2179 }
2180 else if( addr->sa_family == AF_INET6 )
2181 {
2182 size = sizeof( struct sockaddr_in6 );
2183 }
2184 else
2185 {
2186 WSASetLastError( WSAEAFNOSUPPORT );
2187 inBuffer = NULL;
2188 goto exit;
2189 }
2190 }
2191 else
2192 {
2193 size = (DWORD) inAddrSize;
2194 }
2195
2196 stringSize = (DWORD) inBufferSize;
2197 err = WSAAddressToStringA( (LPSOCKADDR) inAddr, size, NULL, inBuffer, &stringSize );
2198 if( err )
2199 {
2200 inBuffer = NULL;
2201 }
2202
2203 exit:
2204 return( inBuffer );
2205 }
2206 #endif // !defined( _WIN32_WCE )