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