2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.24 2005/01/27 20:02:43 cheshire
27 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
29 Revision 1.23 2005/01/25 08:14:15 shersche
30 Change CacheRecord to CacheEntity
32 Revision 1.22 2004/12/10 13:18:40 cheshire
33 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
35 Revision 1.21 2004/11/10 04:03:41 shersche
36 Remove SharedAccess dependency. This causes problems on XP SP1, and isn't necessary for XP SP2 because we already are dependent on WMI, which itself is dependent on SharedAccess.
38 Revision 1.20 2004/10/14 21:44:05 shersche
39 <rdar://problem/3838237> Fix a race condition between the socket thread and the main processing thread that resulted in the socket thread accessing a previously deleted Win32EventSource object.
42 Revision 1.19 2004/10/12 17:59:55 shersche
43 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
46 Revision 1.18 2004/10/11 21:57:50 shersche
47 <rdar://problem/3832450> The SharedAccess service dependency causes a circular dependency on Windows Server 2003. Only add the SharedAccess service dependency if running on XP. All other platforms do not manipulate the firewall and thus are not dependent on it.
50 Revision 1.17 2004/09/17 01:08:58 cheshire
51 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
52 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
53 declared in that file are ONLY appropriate to single-address-space embedded applications.
54 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
56 Revision 1.16 2004/09/16 18:49:34 shersche
57 Remove the XP SP2 check before attempting to manage the firewall. There is a race condition in the SP2 updater such that upon first reboot after the upgrade, mDNSResponder might not know that it is running under SP2 yet. This necessitates a second reboot before the firewall is managed. Removing the check will cause mDNSResponder to try and manage the firewall everytime it boots up, if and only if it hasn't managed the firewall a previous time.
59 Revision 1.15 2004/09/15 17:13:33 shersche
60 Change Firewall name from "Apple mDNSResponder" to "Rendezvous"
62 Revision 1.14 2004/09/15 09:37:25 shersche
63 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
65 Revision 1.13 2004/09/13 07:35:10 shersche
66 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
69 Revision 1.12 2004/09/11 21:18:32 shersche
70 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
73 Revision 1.11 2004/09/11 05:39:19 shersche
74 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
77 Revision 1.10 2004/08/16 21:45:24 shersche
78 Use the full pathname of executable when calling CreateService()
79 Submitted by: prepin@zetron.com
81 Revision 1.9 2004/08/11 01:59:41 cheshire
82 Remove "mDNS *globalInstance" parameter from udsserver_init()
84 Revision 1.8 2004/08/05 05:40:05 shersche
85 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
86 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
87 Bug #: 3751481, 3751566
89 Revision 1.7 2004/07/26 05:35:07 shersche
90 ignore non-enet interfaces when setting up link-local routing
92 Revision 1.6 2004/07/20 06:48:26 shersche
93 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
96 Revision 1.5 2004/07/09 19:08:07 shersche
97 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
100 Revision 1.4 2004/06/24 20:58:15 shersche
101 Fix compiler error in Release build
102 Submitted by: herscher
104 Revision 1.3 2004/06/24 15:28:53 shersche
105 Automatically setup routes to link-local addresses upon interface list change events.
106 Submitted by: herscher
108 Revision 1.2 2004/06/23 16:56:00 shersche
109 <rdar://problem/3697326> locked call to udsserver_idle().
111 Submitted by: herscher
113 Revision 1.1 2004/06/18 04:16:41 rpantos
116 Revision 1.1 2004/01/30 02:58:39 bradley
117 mDNSResponder Windows Service. Provides global Rendezvous support with an IPC interface.
125 #include "CommonServices.h"
126 #include "DebugServices.h"
128 #include "uds_daemon.h"
129 #include "GenLinkedList.h"
131 #include "Resource.h"
133 #include "mDNSEmbeddedAPI.h"
134 #include "mDNSWin32.h"
136 #include "Firewall.h"
138 #if( !TARGET_OS_WINDOWS_CE )
141 #include <ipExport.h>
142 #include <iphlpapi.h>
147 #pragma mark == Constants ==
150 //===========================================================================================================================
152 //===========================================================================================================================
154 #define DEBUG_NAME "[Server] "
155 #define kServiceName "Apple mDNSResponder"
156 #define kServiceFirewallName L"Rendezvous"
157 #define kServiceDependencies "Tcpip\0winmgmt\0\0"
158 #define kServiceManageLLRouting "ManageLLRouting"
159 #define kServiceCacheEntryCount "CacheEntryCount"
160 #define kServiceManageFirewall "ManageFirewall"
161 #define kDNSServiceCacheEntryCountDefault 512
163 #define RR_CACHE_SIZE 500
164 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
166 #pragma mark == Structures ==
169 //===========================================================================================================================
171 //===========================================================================================================================
172 //---------------------------------------------------------------------------------------------------------------------------
173 /*! @typedef EventSourceFlags
175 @abstract Session flags.
177 @constant EventSourceFlagsNone No flags.
178 @constant EventSourceFlagsThreadDone Thread is no longer active.
179 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
180 @constant EventSourceFinalized Finalize has been called for this session
183 typedef uint32_t EventSourceFlags
;
185 #define EventSourceFlagsNone 0
186 #define EventSourceFlagsThreadDone ( 1 << 2 )
187 #define EventSourceFlagsNoClose ( 1 << 3 )
188 #define EventSourceFinalized ( 1 << 4 )
191 typedef struct Win32EventSource
193 EventSourceFlags flags
;
198 udsEventCallback callback
;
203 struct Win32EventSource
* next
;
208 #pragma mark == Prototypes ==
211 //===========================================================================================================================
213 //===========================================================================================================================
215 int __cdecl
main( int argc
, char *argv
[] );
216 static void Usage( void );
217 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
218 static OSStatus
InstallService( const char *inName
, const char *inDisplayName
, const char *inDescription
, const char *inPath
);
219 static OSStatus
RemoveService( const char *inName
);
220 static OSStatus
SetServiceParameters();
221 static OSStatus
GetServiceParameters();
222 static OSStatus
CheckFirewall();
223 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, const char *inServiceName
, const char *inDescription
);
224 static void ReportStatus( int inType
, const char *inFormat
, ... );
225 static OSStatus
RunDirect( int argc
, char *argv
[] );
227 static void WINAPI
ServiceMain( DWORD argc
, LPSTR argv
[] );
228 static OSStatus
ServiceSetupEventLogging( void );
229 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
231 static OSStatus
ServiceRun( int argc
, char *argv
[] );
232 static void ServiceStop( void );
234 static OSStatus
ServiceSpecificInitialize( int argc
, char *argv
[] );
235 static OSStatus
ServiceSpecificRun( int argc
, char *argv
[] );
236 static OSStatus
ServiceSpecificStop( void );
237 static void ServiceSpecificFinalize( int argc
, char *argv
[] );
238 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
239 static void EventSourceLock();
240 static void EventSourceUnlock();
241 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
242 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
243 static void HostDescriptionChanged(mDNS
* const inMDNS
);
244 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
245 static bool HaveLLRoute(PMIB_IPFORWARDROW rowExtant
);
246 static OSStatus
SetLLRoute();
248 #define kLLNetworkAddr "169.254.0.0"
249 #define kLLNetworkAddrMask "255.255.0.0"
252 #include "mDNSEmbeddedAPI.h"
255 #pragma mark == Globals ==
258 //===========================================================================================================================
260 //===========================================================================================================================
261 #define gMDNSRecord mDNSStorage
262 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
263 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
264 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
266 { kServiceName
, ServiceMain
},
269 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
270 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
271 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
272 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
273 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
274 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
275 DEBUG_LOCAL
int gWaitCount
= 0;
276 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
277 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
278 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
279 DEBUG_LOCAL GenLinkedList gEventSources
;
286 //===========================================================================================================================
288 //===========================================================================================================================
290 int __cdecl
main( int argc
, char *argv
[] )
297 debug_initialize( kDebugOutputTypeMetaConsole
);
298 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
300 // Default to automatically starting the service dispatcher if no extra arguments are specified.
302 start
= ( argc
<= 1 );
306 for( i
= 1; i
< argc
; ++i
)
308 if( strcmp( argv
[ i
], "-install" ) == 0 ) // Install
313 LoadStringA( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
314 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[ 0 ] );
317 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
321 else if( strcmp( argv
[ i
], "-remove" ) == 0 ) // Remove
323 err
= RemoveService( kServiceName
);
326 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
330 else if( strcmp( argv
[ i
], "-start" ) == 0 ) // Start
334 else if( strcmp( argv
[ i
], "-server" ) == 0 ) // Server
336 err
= RunDirect( argc
, argv
);
339 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
343 else if( strcmp( argv
[ i
], "-q" ) == 0 ) // Quiet Mode (toggle)
345 gServiceQuietMode
= !gServiceQuietMode
;
347 else if( strcmp( argv
[ i
], "-remote" ) == 0 ) // Allow Remote Connections
349 gServiceAllowRemote
= true;
351 else if( strcmp( argv
[ i
], "-cache" ) == 0 ) // Number of mDNS cache entries
355 ReportStatus( EVENTLOG_ERROR_TYPE
, "-cache used, but number of cache entries not specified\n" );
359 gServiceCacheEntryCount
= atoi( argv
[ ++i
] );
361 else if( ( strcmp( argv
[ i
], "-help" ) == 0 ) || // Help
362 ( strcmp( argv
[ i
], "-h" ) == 0 ) )
376 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
377 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
378 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
382 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
383 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
386 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
393 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
397 //===========================================================================================================================
399 //===========================================================================================================================
401 static void Usage( void )
403 fprintf( stderr
, "\n" );
404 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
405 fprintf( stderr
, "\n" );
406 fprintf( stderr
, " <no args> Runs the service normally\n" );
407 fprintf( stderr
, " -install Creates the service and starts it\n" );
408 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
409 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
410 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
411 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
412 fprintf( stderr
, " -remote Allow remote connections\n" );
413 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
414 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
415 fprintf( stderr
, "\n" );
418 //===========================================================================================================================
419 // ConsoleControlHandler
420 //===========================================================================================================================
422 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
428 switch( inControlEvent
)
431 case CTRL_BREAK_EVENT
:
432 case CTRL_CLOSE_EVENT
:
433 case CTRL_LOGOFF_EVENT
:
434 case CTRL_SHUTDOWN_EVENT
:
435 err
= ServiceSpecificStop();
436 require_noerr( err
, exit
);
449 //===========================================================================================================================
451 //===========================================================================================================================
453 static OSStatus
InstallService( const char *inName
, const char *inDisplayName
, const char *inDescription
, const char *inPath
)
459 TCHAR fullPath
[ MAX_PATH
];
466 // Get a full path to the executable since a relative path may have been specified.
468 size
= GetFullPathName( inPath
, sizeof( fullPath
), fullPath
, &namePtr
);
469 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
470 require_noerr( err
, exit
);
472 // Create the service and start it.
474 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
475 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
476 require_noerr( err
, exit
);
478 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
479 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
481 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
482 require_noerr( err
, exit
);
484 err
= SetServiceParameters();
489 err
= SetServiceInfo( scm
, inName
, inDescription
);
493 ok
= StartService( service
, 0, NULL
);
494 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
495 require_noerr( err
, exit
);
497 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
503 CloseServiceHandle( service
);
507 CloseServiceHandle( scm
);
512 //===========================================================================================================================
514 //===========================================================================================================================
516 static OSStatus
RemoveService( const char *inName
)
522 SERVICE_STATUS status
;
527 // Open a connection to the service.
529 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
530 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
531 require_noerr( err
, exit
);
533 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
534 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
535 require_noerr( err
, exit
);
537 // Stop the service, if it is not already stopped, then delete it.
539 ok
= QueryServiceStatus( service
, &status
);
540 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
541 require_noerr( err
, exit
);
543 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
545 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
546 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
549 ok
= DeleteService( service
);
550 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
551 require_noerr( err
, exit
);
553 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
559 CloseServiceHandle( service
);
563 CloseServiceHandle( scm
);
570 //===========================================================================================================================
571 // SetServiceParameters
572 //===========================================================================================================================
574 static OSStatus
SetServiceParameters()
577 DWORD valueLen
= sizeof(DWORD
);
586 // Add/Open Parameters section under service entry in registry
588 s
= "SYSTEM\\CurrentControlSet\\Services\\" kServiceName
"\\Parameters";
589 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
590 require_noerr( err
, exit
);
593 // If the value isn't already there, then we create it
595 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
597 if (err
!= ERROR_SUCCESS
)
601 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
602 require_noerr( err
, exit
);
617 //===========================================================================================================================
618 // GetServiceParameters
619 //===========================================================================================================================
621 static OSStatus
GetServiceParameters()
633 // Add/Open Parameters section under service entry in registry
635 s
= "SYSTEM\\CurrentControlSet\\Services\\" kServiceName
"\\Parameters";
636 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
637 require_noerr( err
, exit
);
639 valueLen
= sizeof(DWORD
);
640 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
641 if (err
== ERROR_SUCCESS
)
643 gServiceManageLLRouting
= (value
) ? true : false;
646 valueLen
= sizeof(DWORD
);
647 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
648 if (err
== ERROR_SUCCESS
)
650 gServiceCacheEntryCount
= value
;
664 //===========================================================================================================================
666 //===========================================================================================================================
668 static OSStatus
CheckFirewall()
675 OSStatus err
= kUnknownErr
;
677 // Check to see if we've managed the firewall.
678 // This package might have been installed, then
679 // the OS was upgraded to SP2 or above. If that's
680 // the case, then we need to manipulate the firewall
681 // so networking works correctly.
683 s
= "SYSTEM\\CurrentControlSet\\Services\\" kServiceName
"\\Parameters";
684 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
685 require_noerr( err
, exit
);
687 valueLen
= sizeof(DWORD
);
688 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
690 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
692 wchar_t fullPath
[ MAX_PATH
];
695 // Get a full path to the executable
697 size
= GetModuleFileNameW( NULL
, fullPath
, sizeof( fullPath
) );
698 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
699 require_noerr( err
, exit
);
701 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
702 require_noerr( err
, exit
);
705 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
706 require_noerr( err
, exit
);
721 //===========================================================================================================================
723 //===========================================================================================================================
725 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, const char *inServiceName
, const char *inDescription
)
730 SERVICE_DESCRIPTION description
;
731 SERVICE_FAILURE_ACTIONS actions
;
735 check( inServiceName
);
736 check( inDescription
);
741 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
745 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
746 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
747 require_noerr( err
, exit
);
750 lock
= LockServiceDatabase( inSCM
);
751 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
752 require_noerr( err
, exit
);
754 // Open a handle to the service.
756 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
757 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
758 require_noerr( err
, exit
);
760 // Change the description.
762 description
.lpDescription
= (char *) inDescription
;
763 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
764 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
765 require_noerr( err
, exit
);
767 actions
.dwResetPeriod
= INFINITE
;
768 actions
.lpRebootMsg
= NULL
;
769 actions
.lpCommand
= NULL
;
770 actions
.cActions
= 1;
771 actions
.lpsaActions
= &action
;
773 action
.Type
= SC_ACTION_RESTART
;
775 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
776 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
777 require_noerr( err
, exit
);
782 // Close the service and release the lock.
786 CloseServiceHandle( service
);
790 UnlockServiceDatabase( lock
);
795 //===========================================================================================================================
797 //===========================================================================================================================
799 static void ReportStatus( int inType
, const char *inFormat
, ... )
801 if( !gServiceQuietMode
)
805 va_start( args
, inFormat
);
806 if( gServiceEventSource
)
810 const char * array
[ 1 ];
812 vsprintf( s
, inFormat
, args
);
814 ok
= ReportEvent( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
815 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
821 n
= vfprintf( stderr
, inFormat
, args
);
828 //===========================================================================================================================
830 //===========================================================================================================================
832 static OSStatus
RunDirect( int argc
, char *argv
[] )
840 // Install a Console Control Handler to handle things like control-c signals.
842 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
843 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
844 require_noerr( err
, exit
);
846 err
= ServiceSpecificInitialize( argc
, argv
);
847 require_noerr( err
, exit
);
850 // Run the service. This does not return until the service quits or is stopped.
852 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
854 err
= ServiceSpecificRun( argc
, argv
);
855 require_noerr( err
, exit
);
862 ServiceSpecificFinalize( argc
, argv
);
871 //===========================================================================================================================
873 //===========================================================================================================================
875 static void WINAPI
ServiceMain( DWORD argc
, LPSTR argv
[] )
881 err
= ServiceSetupEventLogging();
884 err
= GetServiceParameters();
887 // Initialize the service status and register the service control handler with the name of the service.
889 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
890 gServiceStatus
.dwCurrentState
= 0;
891 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
892 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
893 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
894 gServiceStatus
.dwCheckPoint
= 0;
895 gServiceStatus
.dwWaitHint
= 0;
897 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
898 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
899 require_noerr( err
, exit
);
901 // Setup the description. This should be done by the installer, but it doesn't support that yet.
904 LoadStringA( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
905 err
= SetServiceInfo( NULL
, kServiceName
, desc
);
908 // Mark the service as starting.
910 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
911 gServiceStatus
.dwCheckPoint
= 0;
912 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
913 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
914 check_translated_errno( ok
, GetLastError(), kParamErr
);
916 // Run the service. This does not return until the service quits or is stopped.
918 err
= ServiceRun( (int) argc
, argv
);
921 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
922 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
925 // Service-specific work is done so mark the service as stopped.
927 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
928 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
929 check_translated_errno( ok
, GetLastError(), kParamErr
);
931 // Note: The service status handle should not be closed according to Microsoft documentation.
934 if( gServiceEventSource
)
936 ok
= DeregisterEventSource( gServiceEventSource
);
937 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
938 gServiceEventSource
= NULL
;
942 //===========================================================================================================================
943 // ServiceSetupEventLogging
944 //===========================================================================================================================
946 static OSStatus
ServiceSetupEventLogging( void )
951 DWORD typesSupported
;
952 char path
[ MAX_PATH
];
957 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
959 s
= "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\" kServiceName
;
960 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
961 require_noerr( err
, exit
);
963 // Add the name to the EventMessageFile subkey.
966 GetModuleFileName( NULL
, path
, MAX_PATH
);
967 n
= (DWORD
)( strlen( path
) + 1 );
968 err
= RegSetValueEx( key
, "EventMessageFile", 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
969 require_noerr( err
, exit
);
971 // Set the supported event types in the TypesSupported subkey.
975 | EVENTLOG_ERROR_TYPE
976 | EVENTLOG_WARNING_TYPE
977 | EVENTLOG_INFORMATION_TYPE
978 | EVENTLOG_AUDIT_SUCCESS
979 | EVENTLOG_AUDIT_FAILURE
;
980 err
= RegSetValueEx( key
, "TypesSupported", 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
981 require_noerr( err
, exit
);
983 // Set up the event source.
985 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
986 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
987 require_noerr( err
, exit
);
997 //===========================================================================================================================
998 // ServiceControlHandler
999 //===========================================================================================================================
1001 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1006 DEBUG_UNUSED( inEventData
);
1007 DEBUG_UNUSED( inContext
);
1012 case SERVICE_CONTROL_STOP
:
1013 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1019 case SERVICE_CONTROL_POWEREVENT
:
1021 if (inEventType
== PBT_APMSUSPEND
)
1023 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1025 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1027 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1033 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1037 if( setStatus
&& gServiceStatusHandle
)
1039 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1040 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1046 //===========================================================================================================================
1048 //===========================================================================================================================
1050 static OSStatus
ServiceRun( int argc
, char *argv
[] )
1056 DEBUG_UNUSED( argc
);
1057 DEBUG_UNUSED( argv
);
1059 initialized
= FALSE
;
1061 // Initialize the service-specific stuff and mark the service as running.
1063 err
= ServiceSpecificInitialize( argc
, argv
);
1064 require_noerr( err
, exit
);
1067 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1068 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1069 check_translated_errno( ok
, GetLastError(), kParamErr
);
1071 err
= CheckFirewall();
1074 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1076 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1077 err
= ServiceSpecificRun( argc
, argv
);
1078 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1079 require_noerr( err
, exit
);
1081 // Service stopped. Clean up and we're done.
1086 ServiceSpecificFinalize( argc
, argv
);
1091 //===========================================================================================================================
1093 //===========================================================================================================================
1095 static void ServiceStop( void )
1100 // Signal the event to cause the service to exit.
1102 if( gServiceStatusHandle
)
1104 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1105 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1106 check_translated_errno( ok
, GetLastError(), kParamErr
);
1109 err
= ServiceSpecificStop();
1115 #pragma mark == Service Specific ==
1118 //===========================================================================================================================
1119 // ServiceSpecificInitialize
1120 //===========================================================================================================================
1122 static OSStatus
ServiceSpecificInitialize( int argc
, char *argv
[] )
1126 DEBUG_UNUSED( argc
);
1127 DEBUG_UNUSED( argv
);
1129 memset( &gMDNSRecord
, 0, sizeof gMDNSRecord
);
1130 memset( &gPlatformStorage
, 0, sizeof gPlatformStorage
);
1132 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1133 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1135 InitializeCriticalSection(&gEventSourceLock
);
1137 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1138 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1139 require_noerr( err
, exit
);
1141 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1142 require_noerr( err
, exit
);
1144 err
= udsserver_init();
1145 require_noerr( err
, exit
);
1148 // set a route to link local addresses (169.254.0.0)
1150 if (gServiceManageLLRouting
== true)
1158 ServiceSpecificFinalize( argc
, argv
);
1163 //===========================================================================================================================
1164 // ServiceSpecificRun
1165 //===========================================================================================================================
1167 static OSStatus
ServiceSpecificRun( int argc
, char *argv
[] )
1171 DEBUG_UNUSED( argc
);
1172 DEBUG_UNUSED( argv
);
1174 // Main event loop. Process connection requests and state changes (i.e. quit).
1175 while( (result
= WaitForSingleObject(gStopEvent
, INFINITE
)) != WAIT_OBJECT_0
)
1177 // Unexpected wait result.
1178 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1184 //===========================================================================================================================
1185 // ServiceSpecificStop
1186 //===========================================================================================================================
1188 static OSStatus
ServiceSpecificStop( void )
1193 ok
= SetEvent(gStopEvent
);
1194 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1195 require_noerr( err
, exit
);
1200 //===========================================================================================================================
1201 // ServiceSpecificFinalize
1202 //===========================================================================================================================
1204 static void ServiceSpecificFinalize( int argc
, char *argv
[] )
1206 DEBUG_UNUSED( argc
);
1207 DEBUG_UNUSED( argv
);
1210 // clean up any open sessions
1212 while (gEventSources
.Head
)
1214 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1217 // give a chance for the udsserver code to clean up
1222 // and finally close down the mDNSCore
1224 mDNS_Close(&gMDNSRecord
);
1227 // clean up the event sources mutex...no one should be using it now
1229 DeleteCriticalSection(&gEventSourceLock
);
1234 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1236 DEBUG_UNUSED( inMDNS
);
1238 if (status
== mStatus_ConfigChanged
)
1240 if (gServiceManageLLRouting
== true)
1249 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1251 DEBUG_UNUSED( inMDNS
);
1254 // rdar://problem/3697326
1256 // udsserver_idle wasn't being locked. This resulted
1257 // in multiple threads contesting for the all_requests
1258 // data structure in uds_daemon.c
1260 mDNSPlatformLock(&gMDNSRecord
);
1262 interval
= udsserver_idle(interval
);
1264 mDNSPlatformUnlock(&gMDNSRecord
);
1271 HostDescriptionChanged(mDNS
* const inMDNS
)
1273 DEBUG_UNUSED( inMDNS
);
1275 udsserver_handle_configchange();
1279 mDNSlocal
unsigned WINAPI
1280 udsSocketThread(LPVOID inParam
)
1282 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1283 DWORD threadID
= GetCurrentThreadId();
1288 bool locked
= false;
1291 waitCount
= source
->waitCount
;
1292 waitList
[0] = source
->waitList
[0];
1293 waitList
[1] = source
->waitList
[1];
1294 done
= (bool) (source
->flags
& EventSourceFinalized
);
1300 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1302 mDNSPlatformLock(&gMDNSRecord
);
1305 // <rdar://problem/3838237>
1307 // Look up the source by the thread id. This will ensure that the
1308 // source is still extant. It could already have been deleted
1309 // by the processing thread.
1314 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1316 if (source
->threadID
== threadID
)
1322 EventSourceUnlock();
1332 if (result
== WAIT_OBJECT_0
)
1334 source
->callback(source
->context
);
1339 else if (result
== WAIT_OBJECT_0
+ 1)
1342 // this is a bit of a hack. we want to clean up the internal data structures
1343 // so we'll go in here and it will clean up for us
1345 shutdown(source
->sock
, 2);
1346 source
->callback(source
->context
);
1352 // Unexpected wait result.
1353 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1357 done
= (bool) (source
->flags
& EventSourceFinalized
);
1359 mDNSPlatformUnlock(&gMDNSRecord
);
1364 source
->flags
|= EventSourceFlagsThreadDone
;
1365 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1366 EventSourceUnlock();
1370 EventSourceFinalize( source
);
1377 mDNSPlatformUnlock(&gMDNSRecord
);
1380 _endthreadex_compat( (unsigned) err
);
1381 return( (unsigned) err
);
1386 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1388 Win32EventSource
* newSource
;
1392 newSource
= malloc(sizeof(Win32EventSource
));
1393 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1394 memset(newSource
, 0, sizeof(Win32EventSource
));
1396 newSource
->flags
= 0;
1397 newSource
->sock
= (SOCKET
) fd
;
1398 newSource
->callback
= callback
;
1399 newSource
->context
= context
;
1401 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1402 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1403 require_noerr( err
, exit
);
1405 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1406 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1407 require_noerr( err
, exit
);
1409 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1410 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1411 require_noerr( err
, exit
);
1413 newSource
->waitCount
= 0;
1414 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1415 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1422 // add the event source to the end of the list, while checking
1423 // to see if the list needs to be initialized
1425 if ( gEventSources
.LinkOffset
== 0)
1427 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1430 AddToTail( &gEventSources
, newSource
);
1433 // no longer using the list
1435 EventSourceUnlock();
1437 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1438 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1439 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1440 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1441 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1442 require_noerr( err
, exit
);
1444 result
= ResumeThread( newSource
->threadHandle
);
1445 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1446 require_noerr( err
, exit
);
1450 if (err
&& newSource
)
1452 EventSourceFinalize(newSource
);
1460 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1462 Win32EventSource
* source
;
1463 mStatus err
= mStatus_NoError
;
1466 // find the event source
1470 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1472 if (source
->sock
== (SOCKET
) fd
)
1479 // if we found him, finalize him
1483 EventSourceFinalize(source
);
1487 // done with the list
1489 EventSourceUnlock();
1497 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1506 EventSourceFinalize(Win32EventSource
* source
)
1510 Win32EventSource
* inserted
;
1519 // Find the session in the list.
1524 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1526 if( inserted
== source
)
1531 require_action( inserted
, exit
, err
= kNotFoundErr
);
1534 // note that we've had finalize called
1536 source
->flags
|= EventSourceFinalized
;
1538 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1539 // we must defer the close until the thread is done because the thread is still using the session object.
1542 threadID
= GetCurrentThreadId();
1543 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1544 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1546 source
->flags
&= ~EventSourceFlagsNoClose
;
1550 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1551 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1552 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1554 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1559 // Signal a close so the thread exits.
1561 if( source
->closeEvent
)
1563 ok
= SetEvent( source
->closeEvent
);
1564 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1572 source
->flags
|= EventSourceFlagsNoClose
;
1574 // Remove the session from the list.
1575 RemoveFromList(&gEventSources
, source
);
1577 EventSourceUnlock();
1580 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1582 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1584 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1585 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1588 // Release the thread.
1590 if( source
->threadHandle
)
1592 ok
= CloseHandle( source
->threadHandle
);
1593 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1594 source
->threadHandle
= NULL
;
1597 // Release the socket event.
1599 if( source
->socketEvent
)
1601 ok
= CloseHandle( source
->socketEvent
);
1602 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1603 source
->socketEvent
= NULL
;
1606 // Release the close event.
1608 if( source
->closeEvent
)
1610 ok
= CloseHandle( source
->closeEvent
);
1611 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1612 source
->closeEvent
= NULL
;
1615 // Release the memory used by the object.
1620 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1626 EventSourceUnlock();
1636 EnterCriticalSection(&gEventSourceLock
);
1643 LeaveCriticalSection(&gEventSourceLock
);
1647 //===========================================================================================================================
1649 //===========================================================================================================================
1652 HaveLLRoute(PMIB_IPFORWARDROW rowExtant
)
1654 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
1656 BOOL bOrder
= FALSE
;
1659 unsigned long int i
;
1662 // Find out how big our buffer needs to be.
1664 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
1665 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
1668 // Allocate the memory for the table
1670 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
1671 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
1674 // Now get the table.
1676 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
1677 require_noerr( err
, exit
);
1680 // Search for the row in the table we want.
1682 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
1684 if (pIpForwardTable
->table
[i
].dwForwardDest
== inet_addr(kLLNetworkAddr
))
1686 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
1694 if ( pIpForwardTable
!= NULL
)
1696 free(pIpForwardTable
);
1703 //===========================================================================================================================
1705 //===========================================================================================================================
1711 MIB_IPFORWARDROW rowExtant
;
1713 MIB_IPFORWARDROW row
;
1716 ZeroMemory(&row
, sizeof(row
));
1718 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
1719 require_noerr( err
, exit
);
1720 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
1721 row
.dwForwardIfIndex
= ifIndex
;
1722 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
1723 row
.dwForwardType
= 3;
1724 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1725 row
.dwForwardAge
= 0;
1726 row
.dwForwardPolicy
= 0;
1727 row
.dwForwardMetric1
= 30;
1728 row
.dwForwardMetric2
= (DWORD
) - 1;
1729 row
.dwForwardMetric3
= (DWORD
) - 1;
1730 row
.dwForwardMetric4
= (DWORD
) - 1;
1731 row
.dwForwardMetric5
= (DWORD
) - 1;
1736 // check to make sure we don't already have a route
1738 if (HaveLLRoute(&rowExtant
))
1741 // set the age to 0 so that we can do a memcmp.
1743 rowExtant
.dwForwardAge
= 0;
1746 // check to see if this route is the same as our route
1748 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
1751 // if it isn't then delete this entry
1753 DeleteIpForwardEntry(&rowExtant
);
1758 // else it is, so we don't want to create another route
1764 if (addRoute
&& row
.dwForwardNextHop
)
1766 err
= CreateIpForwardEntry(&row
);
1768 require_noerr( err
, exit
);
1772 // see if this address is a link local address
1774 if ((row
.dwForwardNextHop
& 0xFFFF) == row
.dwForwardDest
)
1777 // if so, set up a route to ARP everything
1779 row
.dwForwardDest
= 0;
1780 row
.dwForwardIfIndex
= ifIndex
;
1781 row
.dwForwardMask
= 0;
1782 row
.dwForwardType
= 3;
1783 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1784 row
.dwForwardAge
= 0;
1785 row
.dwForwardPolicy
= 0;
1786 row
.dwForwardMetric1
= 1;
1787 row
.dwForwardMetric2
= (DWORD
) - 1;
1788 row
.dwForwardMetric3
= (DWORD
) - 1;
1789 row
.dwForwardMetric4
= (DWORD
) - 1;
1790 row
.dwForwardMetric5
= (DWORD
) - 1;
1792 err
= CreateIpForwardEntry(&row
);
1794 require_noerr( err
, exit
);
1802 //===========================================================================================================================
1803 // GetRouteDestination
1804 //===========================================================================================================================
1807 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
1810 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1811 IP_ADAPTER_INFO
* pAdapter
= NULL
;
1816 // GetBestInterface will fail if there is no default gateway
1817 // configured. If that happens, we will just take the first
1818 // interface in the list. MSDN support says there is no surefire
1819 // way to manually determine what the best interface might
1820 // be for a particular network address.
1822 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
1823 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
1831 // Make an initial call to GetAdaptersInfo to get
1832 // the necessary size into the bufLen variable
1834 err
= GetAdaptersInfo( NULL
, &bufLen
);
1835 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
1837 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
1838 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1840 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1841 require_noerr( err
, exit
);
1843 pAdapter
= pAdapterInfo
;
1846 // <rdar://problem/3718122>
1848 // Look for the Nortel VPN virtual interface. This interface
1849 // is identified by it's unique MAC address: 44-45-53-54-42-00
1851 // If the interface is active (i.e., has a non-zero IP Address),
1852 // then we want to disable routing table modifications.
1856 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
1857 (pAdapter
->AddressLength
== 6) &&
1858 (pAdapter
->Address
[0] == 0x44) &&
1859 (pAdapter
->Address
[1] == 0x45) &&
1860 (pAdapter
->Address
[2] == 0x53) &&
1861 (pAdapter
->Address
[3] == 0x54) &&
1862 (pAdapter
->Address
[4] == 0x42) &&
1863 (pAdapter
->Address
[5] == 0x00) &&
1864 (inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0))
1869 pAdapter
= pAdapter
->Next
;
1872 pAdapter
= pAdapterInfo
;
1878 // if we don't have an interface selected, choose the first one
1880 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
1882 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
1883 *ifIndex
= pAdapter
->Index
;
1888 pAdapter
= pAdapter
->Next
;
1893 if ( pAdapterInfo
!= NULL
)
1895 free( pAdapterInfo
);