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.29 2005/03/06 05:21:56 shersche
27 <rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
29 Revision 1.28 2005/03/03 02:27:24 shersche
30 Include the RegNames.h header file for names of registry keys
32 Revision 1.27 2005/03/02 20:12:59 shersche
35 Revision 1.26 2005/02/15 08:00:27 shersche
36 <rdar://problem/4007151> Update name
38 Revision 1.25 2005/02/10 22:35:36 cheshire
39 <rdar://problem/3727944> Update name
41 Revision 1.24 2005/01/27 20:02:43 cheshire
42 udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
44 Revision 1.23 2005/01/25 08:14:15 shersche
45 Change CacheRecord to CacheEntity
47 Revision 1.22 2004/12/10 13:18:40 cheshire
48 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
50 Revision 1.21 2004/11/10 04:03:41 shersche
51 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.
53 Revision 1.20 2004/10/14 21:44:05 shersche
54 <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.
57 Revision 1.19 2004/10/12 17:59:55 shersche
58 <rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
61 Revision 1.18 2004/10/11 21:57:50 shersche
62 <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.
65 Revision 1.17 2004/09/17 01:08:58 cheshire
66 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
67 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
68 declared in that file are ONLY appropriate to single-address-space embedded applications.
69 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
71 Revision 1.16 2004/09/16 18:49:34 shersche
72 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.
74 Revision 1.15 2004/09/15 17:13:33 shersche
77 Revision 1.14 2004/09/15 09:37:25 shersche
78 Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
80 Revision 1.13 2004/09/13 07:35:10 shersche
81 <rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
84 Revision 1.12 2004/09/11 21:18:32 shersche
85 <rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
88 Revision 1.11 2004/09/11 05:39:19 shersche
89 <rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
92 Revision 1.10 2004/08/16 21:45:24 shersche
93 Use the full pathname of executable when calling CreateService()
94 Submitted by: prepin@zetron.com
96 Revision 1.9 2004/08/11 01:59:41 cheshire
97 Remove "mDNS *globalInstance" parameter from udsserver_init()
99 Revision 1.8 2004/08/05 05:40:05 shersche
100 <rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
101 <rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
102 Bug #: 3751481, 3751566
104 Revision 1.7 2004/07/26 05:35:07 shersche
105 ignore non-enet interfaces when setting up link-local routing
107 Revision 1.6 2004/07/20 06:48:26 shersche
108 <rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
111 Revision 1.5 2004/07/09 19:08:07 shersche
112 <rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
115 Revision 1.4 2004/06/24 20:58:15 shersche
116 Fix compiler error in Release build
117 Submitted by: herscher
119 Revision 1.3 2004/06/24 15:28:53 shersche
120 Automatically setup routes to link-local addresses upon interface list change events.
121 Submitted by: herscher
123 Revision 1.2 2004/06/23 16:56:00 shersche
124 <rdar://problem/3697326> locked call to udsserver_idle().
126 Submitted by: herscher
128 Revision 1.1 2004/06/18 04:16:41 rpantos
131 Revision 1.1 2004/01/30 02:58:39 bradley
132 mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
140 #include "CommonServices.h"
141 #include "DebugServices.h"
142 #include "RegNames.h"
144 #include "uds_daemon.h"
145 #include "GenLinkedList.h"
147 #include "Resource.h"
149 #include "mDNSEmbeddedAPI.h"
150 #include "mDNSWin32.h"
152 #include "Firewall.h"
154 #if( !TARGET_OS_WINDOWS_CE )
157 #include <ipExport.h>
158 #include <iphlpapi.h>
163 #pragma mark == Constants ==
166 //===========================================================================================================================
168 //===========================================================================================================================
170 #define DEBUG_NAME "[Server] "
171 #define kServiceFirewallName L"Bonjour"
172 #define kServiceDependencies TEXT("Tcpip\0winmgmt\0\0")
173 #define kDNSServiceCacheEntryCountDefault 512
175 #define RR_CACHE_SIZE 500
176 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
178 #pragma mark == Structures ==
181 //===========================================================================================================================
183 //===========================================================================================================================
184 //---------------------------------------------------------------------------------------------------------------------------
185 /*! @typedef EventSourceFlags
187 @abstract Session flags.
189 @constant EventSourceFlagsNone No flags.
190 @constant EventSourceFlagsThreadDone Thread is no longer active.
191 @constant EventSourceFlagsNoClose Do not close the session when the thread exits.
192 @constant EventSourceFinalized Finalize has been called for this session
195 typedef uint32_t EventSourceFlags
;
197 #define EventSourceFlagsNone 0
198 #define EventSourceFlagsThreadDone ( 1 << 2 )
199 #define EventSourceFlagsNoClose ( 1 << 3 )
200 #define EventSourceFinalized ( 1 << 4 )
203 typedef struct Win32EventSource
205 EventSourceFlags flags
;
210 udsEventCallback callback
;
215 struct Win32EventSource
* next
;
220 #pragma mark == Prototypes ==
223 //===========================================================================================================================
225 //===========================================================================================================================
227 int __cdecl
wmain( int argc
, LPTSTR argv
[] );
229 int __cdecl
main( int argc
, char *argv
[] );
231 static void Usage( void );
232 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
233 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
234 static OSStatus
RemoveService( LPCTSTR inName
);
235 static OSStatus
SetServiceParameters();
236 static OSStatus
GetServiceParameters();
237 static OSStatus
CheckFirewall();
238 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
239 static void ReportStatus( int inType
, const char *inFormat
, ... );
240 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] );
242 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
243 static OSStatus
ServiceSetupEventLogging( void );
244 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
246 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
247 static void ServiceStop( void );
249 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
250 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
251 static OSStatus
ServiceSpecificStop( void );
252 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
253 static mStatus
EventSourceFinalize(Win32EventSource
* source
);
254 static void EventSourceLock();
255 static void EventSourceUnlock();
256 static mDNSs32
udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
);
257 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
258 static void HostDescriptionChanged(mDNS
* const inMDNS
);
259 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
260 static bool HaveLLRoute(PMIB_IPFORWARDROW rowExtant
);
261 static OSStatus
SetLLRoute();
264 # define StrLen(X) wcslen(X)
265 # define StrCmp(X,Y) wcscmp(X,Y)
267 # define StrLen(X) strlen(X)
268 # define StrCmp(X,Y) strcmp(X,Y)
272 #define kLLNetworkAddr "169.254.0.0"
273 #define kLLNetworkAddrMask "255.255.0.0"
276 #include "mDNSEmbeddedAPI.h"
279 #pragma mark == Globals ==
282 //===========================================================================================================================
284 //===========================================================================================================================
285 #define gMDNSRecord mDNSStorage
286 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
287 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
288 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
290 { kServiceName
, ServiceMain
},
293 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
294 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
295 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
296 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
297 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
298 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
299 DEBUG_LOCAL
int gWaitCount
= 0;
300 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
301 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
302 DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock
;
303 DEBUG_LOCAL GenLinkedList gEventSources
;
310 //===========================================================================================================================
312 //===========================================================================================================================
314 int __cdecl
wmain( int argc
, wchar_t * argv
[] )
316 int __cdecl
main( int argc
, char *argv
[] )
324 debug_initialize( kDebugOutputTypeMetaConsole
);
325 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
327 // Default to automatically starting the service dispatcher if no extra arguments are specified.
329 start
= ( argc
<= 1 );
333 for( i
= 1; i
< argc
; ++i
)
335 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
340 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
341 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
344 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
348 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
350 err
= RemoveService( kServiceName
);
353 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
357 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
361 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
363 err
= RunDirect( argc
, argv
);
366 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
370 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
372 gServiceQuietMode
= !gServiceQuietMode
;
374 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
375 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
389 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
390 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
391 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
395 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
396 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
399 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
406 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
410 //===========================================================================================================================
412 //===========================================================================================================================
414 static void Usage( void )
416 fprintf( stderr
, "\n" );
417 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
418 fprintf( stderr
, "\n" );
419 fprintf( stderr
, " <no args> Runs the service normally\n" );
420 fprintf( stderr
, " -install Creates the service and starts it\n" );
421 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
422 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
423 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
424 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
425 fprintf( stderr
, " -remote Allow remote connections\n" );
426 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
427 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
428 fprintf( stderr
, "\n" );
431 //===========================================================================================================================
432 // ConsoleControlHandler
433 //===========================================================================================================================
435 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
441 switch( inControlEvent
)
444 case CTRL_BREAK_EVENT
:
445 case CTRL_CLOSE_EVENT
:
446 case CTRL_LOGOFF_EVENT
:
447 case CTRL_SHUTDOWN_EVENT
:
448 err
= ServiceSpecificStop();
449 require_noerr( err
, exit
);
462 //===========================================================================================================================
464 //===========================================================================================================================
466 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
472 TCHAR fullPath
[ MAX_PATH
];
479 // Get a full path to the executable since a relative path may have been specified.
481 size
= GetFullPathName( inPath
, sizeof( fullPath
), fullPath
, &namePtr
);
482 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
483 require_noerr( err
, exit
);
485 // Create the service and start it.
487 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
488 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
489 require_noerr( err
, exit
);
491 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
492 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
494 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
495 require_noerr( err
, exit
);
497 err
= SetServiceParameters();
502 err
= SetServiceInfo( scm
, inName
, inDescription
);
506 ok
= StartService( service
, 0, NULL
);
507 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
508 require_noerr( err
, exit
);
510 ReportStatus( EVENTLOG_SUCCESS
, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName
, inDisplayName
, inPath
);
516 CloseServiceHandle( service
);
520 CloseServiceHandle( scm
);
525 //===========================================================================================================================
527 //===========================================================================================================================
529 static OSStatus
RemoveService( LPCTSTR inName
)
535 SERVICE_STATUS status
;
540 // Open a connection to the service.
542 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
543 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
544 require_noerr( err
, exit
);
546 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
547 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
548 require_noerr( err
, exit
);
550 // Stop the service, if it is not already stopped, then delete it.
552 ok
= QueryServiceStatus( service
, &status
);
553 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
554 require_noerr( err
, exit
);
556 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
558 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
559 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
562 ok
= DeleteService( service
);
563 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
564 require_noerr( err
, exit
);
566 ReportStatus( EVENTLOG_SUCCESS
, "Removed service \"%s\"\n", inName
);
572 CloseServiceHandle( service
);
576 CloseServiceHandle( scm
);
583 //===========================================================================================================================
584 // SetServiceParameters
585 //===========================================================================================================================
587 static OSStatus
SetServiceParameters()
590 DWORD valueLen
= sizeof(DWORD
);
599 // Add/Open Parameters section under service entry in registry
601 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters");
602 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
603 require_noerr( err
, exit
);
606 // If the value isn't already there, then we create it
608 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
610 if (err
!= ERROR_SUCCESS
)
614 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
615 require_noerr( err
, exit
);
630 //===========================================================================================================================
631 // GetServiceParameters
632 //===========================================================================================================================
634 static OSStatus
GetServiceParameters()
646 // Add/Open Parameters section under service entry in registry
648 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters");
649 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
650 require_noerr( err
, exit
);
652 valueLen
= sizeof(DWORD
);
653 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
654 if (err
== ERROR_SUCCESS
)
656 gServiceManageLLRouting
= (value
) ? true : false;
659 valueLen
= sizeof(DWORD
);
660 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
661 if (err
== ERROR_SUCCESS
)
663 gServiceCacheEntryCount
= value
;
677 //===========================================================================================================================
679 //===========================================================================================================================
681 static OSStatus
CheckFirewall()
688 OSStatus err
= kUnknownErr
;
690 // Check to see if we've managed the firewall.
691 // This package might have been installed, then
692 // the OS was upgraded to SP2 or above. If that's
693 // the case, then we need to manipulate the firewall
694 // so networking works correctly.
696 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\") kServiceName
TEXT("\\Parameters");
697 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
698 require_noerr( err
, exit
);
700 valueLen
= sizeof(DWORD
);
701 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
703 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
705 wchar_t fullPath
[ MAX_PATH
];
708 // Get a full path to the executable
710 size
= GetModuleFileNameW( NULL
, fullPath
, sizeof( fullPath
) );
711 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
712 require_noerr( err
, exit
);
714 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
715 require_noerr( err
, exit
);
718 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
719 require_noerr( err
, exit
);
734 //===========================================================================================================================
736 //===========================================================================================================================
738 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
743 SERVICE_DESCRIPTION description
;
744 SERVICE_FAILURE_ACTIONS actions
;
748 check( inServiceName
);
749 check( inDescription
);
754 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
758 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
759 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
760 require_noerr( err
, exit
);
763 lock
= LockServiceDatabase( inSCM
);
764 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
765 require_noerr( err
, exit
);
767 // Open a handle to the service.
769 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
770 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
771 require_noerr( err
, exit
);
773 // Change the description.
775 description
.lpDescription
= (LPTSTR
) inDescription
;
776 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
777 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
778 require_noerr( err
, exit
);
780 actions
.dwResetPeriod
= INFINITE
;
781 actions
.lpRebootMsg
= NULL
;
782 actions
.lpCommand
= NULL
;
783 actions
.cActions
= 1;
784 actions
.lpsaActions
= &action
;
786 action
.Type
= SC_ACTION_RESTART
;
788 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
789 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
790 require_noerr( err
, exit
);
795 // Close the service and release the lock.
799 CloseServiceHandle( service
);
803 UnlockServiceDatabase( lock
);
808 //===========================================================================================================================
810 //===========================================================================================================================
812 static void ReportStatus( int inType
, const char *inFormat
, ... )
814 if( !gServiceQuietMode
)
818 va_start( args
, inFormat
);
819 if( gServiceEventSource
)
823 const char * array
[ 1 ];
825 vsprintf( s
, inFormat
, args
);
827 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, 0x20000001L
, NULL
, 1, 0, array
, NULL
);
828 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
834 n
= vfprintf( stderr
, inFormat
, args
);
841 //===========================================================================================================================
843 //===========================================================================================================================
845 static OSStatus
RunDirect( int argc
, LPTSTR argv
[] )
853 // Install a Console Control Handler to handle things like control-c signals.
855 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
856 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
857 require_noerr( err
, exit
);
859 err
= ServiceSpecificInitialize( argc
, argv
);
860 require_noerr( err
, exit
);
863 // Run the service. This does not return until the service quits or is stopped.
865 ReportStatus( EVENTLOG_SUCCESS
, "Running \"%s\" service directly\n", kServiceName
);
867 err
= ServiceSpecificRun( argc
, argv
);
868 require_noerr( err
, exit
);
875 ServiceSpecificFinalize( argc
, argv
);
884 //===========================================================================================================================
886 //===========================================================================================================================
888 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
894 err
= ServiceSetupEventLogging();
897 err
= GetServiceParameters();
900 // Initialize the service status and register the service control handler with the name of the service.
902 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
903 gServiceStatus
.dwCurrentState
= 0;
904 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_POWEREVENT
;
905 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
906 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
907 gServiceStatus
.dwCheckPoint
= 0;
908 gServiceStatus
.dwWaitHint
= 0;
910 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
911 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
912 require_noerr( err
, exit
);
914 // Setup the description. This should be done by the installer, but it doesn't support that yet.
917 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
918 err
= SetServiceInfo( NULL
, kServiceName
, desc
);
921 // Mark the service as starting.
923 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
924 gServiceStatus
.dwCheckPoint
= 0;
925 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
926 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
927 check_translated_errno( ok
, GetLastError(), kParamErr
);
929 // Run the service. This does not return until the service quits or is stopped.
931 err
= ServiceRun( (int) argc
, argv
);
934 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
935 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
938 // Service-specific work is done so mark the service as stopped.
940 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
941 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
942 check_translated_errno( ok
, GetLastError(), kParamErr
);
944 // Note: The service status handle should not be closed according to Microsoft documentation.
947 if( gServiceEventSource
)
949 ok
= DeregisterEventSource( gServiceEventSource
);
950 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
951 gServiceEventSource
= NULL
;
955 //===========================================================================================================================
956 // ServiceSetupEventLogging
957 //===========================================================================================================================
959 static OSStatus
ServiceSetupEventLogging( void )
964 DWORD typesSupported
;
965 TCHAR path
[ MAX_PATH
];
970 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
972 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
973 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
974 require_noerr( err
, exit
);
976 // Add the name to the EventMessageFile subkey.
979 GetModuleFileName( NULL
, path
, MAX_PATH
);
980 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
981 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
982 require_noerr( err
, exit
);
984 // Set the supported event types in the TypesSupported subkey.
988 | EVENTLOG_ERROR_TYPE
989 | EVENTLOG_WARNING_TYPE
990 | EVENTLOG_INFORMATION_TYPE
991 | EVENTLOG_AUDIT_SUCCESS
992 | EVENTLOG_AUDIT_FAILURE
;
993 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
994 require_noerr( err
, exit
);
996 // Set up the event source.
998 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
999 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
1000 require_noerr( err
, exit
);
1010 //===========================================================================================================================
1011 // ServiceControlHandler
1012 //===========================================================================================================================
1014 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1019 DEBUG_UNUSED( inEventData
);
1020 DEBUG_UNUSED( inContext
);
1025 case SERVICE_CONTROL_STOP
:
1026 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
1032 case SERVICE_CONTROL_POWEREVENT
:
1034 if (inEventType
== PBT_APMSUSPEND
)
1036 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1038 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1040 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1046 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1050 if( setStatus
&& gServiceStatusHandle
)
1052 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1053 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1059 //===========================================================================================================================
1061 //===========================================================================================================================
1063 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1069 DEBUG_UNUSED( argc
);
1070 DEBUG_UNUSED( argv
);
1072 initialized
= FALSE
;
1074 // Initialize the service-specific stuff and mark the service as running.
1076 err
= ServiceSpecificInitialize( argc
, argv
);
1077 require_noerr( err
, exit
);
1080 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1081 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1082 check_translated_errno( ok
, GetLastError(), kParamErr
);
1084 err
= CheckFirewall();
1087 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1089 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder started\n" );
1090 err
= ServiceSpecificRun( argc
, argv
);
1091 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "mDNSResponder stopped (%d)\n", err
);
1092 require_noerr( err
, exit
);
1094 // Service stopped. Clean up and we're done.
1099 ServiceSpecificFinalize( argc
, argv
);
1104 //===========================================================================================================================
1106 //===========================================================================================================================
1108 static void ServiceStop( void )
1113 // Signal the event to cause the service to exit.
1115 if( gServiceStatusHandle
)
1117 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1118 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1119 check_translated_errno( ok
, GetLastError(), kParamErr
);
1122 err
= ServiceSpecificStop();
1128 #pragma mark == Service Specific ==
1131 //===========================================================================================================================
1132 // ServiceSpecificInitialize
1133 //===========================================================================================================================
1135 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1139 DEBUG_UNUSED( argc
);
1140 DEBUG_UNUSED( argv
);
1142 memset( &gMDNSRecord
, 0, sizeof gMDNSRecord
);
1143 memset( &gPlatformStorage
, 0, sizeof gPlatformStorage
);
1145 gPlatformStorage
.idleThreadCallback
= udsIdle
;
1146 gPlatformStorage
.hostDescriptionChangedCallback
= HostDescriptionChanged
;
1148 InitializeCriticalSection(&gEventSourceLock
);
1150 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1151 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1152 require_noerr( err
, exit
);
1154 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1155 require_noerr( err
, exit
);
1157 err
= udsserver_init();
1158 require_noerr( err
, exit
);
1161 // set a route to link local addresses (169.254.0.0)
1163 if (gServiceManageLLRouting
== true)
1171 ServiceSpecificFinalize( argc
, argv
);
1176 //===========================================================================================================================
1177 // ServiceSpecificRun
1178 //===========================================================================================================================
1180 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1184 DEBUG_UNUSED( argc
);
1185 DEBUG_UNUSED( argv
);
1187 // Main event loop. Process connection requests and state changes (i.e. quit).
1188 while( (result
= WaitForSingleObject(gStopEvent
, INFINITE
)) != WAIT_OBJECT_0
)
1190 // Unexpected wait result.
1191 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1197 //===========================================================================================================================
1198 // ServiceSpecificStop
1199 //===========================================================================================================================
1201 static OSStatus
ServiceSpecificStop( void )
1206 ok
= SetEvent(gStopEvent
);
1207 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1208 require_noerr( err
, exit
);
1213 //===========================================================================================================================
1214 // ServiceSpecificFinalize
1215 //===========================================================================================================================
1217 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1219 DEBUG_UNUSED( argc
);
1220 DEBUG_UNUSED( argv
);
1223 // clean up any open sessions
1225 while (gEventSources
.Head
)
1227 EventSourceFinalize((Win32EventSource
*) gEventSources
.Head
);
1230 // give a chance for the udsserver code to clean up
1235 // and finally close down the mDNSCore
1237 mDNS_Close(&gMDNSRecord
);
1240 // clean up the event sources mutex...no one should be using it now
1242 DeleteCriticalSection(&gEventSourceLock
);
1247 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1249 DEBUG_UNUSED( inMDNS
);
1251 if (status
== mStatus_ConfigChanged
)
1253 if (gServiceManageLLRouting
== true)
1262 udsIdle(mDNS
* const inMDNS
, mDNSs32 interval
)
1264 DEBUG_UNUSED( inMDNS
);
1267 // rdar://problem/3697326
1269 // udsserver_idle wasn't being locked. This resulted
1270 // in multiple threads contesting for the all_requests
1271 // data structure in uds_daemon.c
1273 mDNSPlatformLock(&gMDNSRecord
);
1275 interval
= udsserver_idle(interval
);
1277 mDNSPlatformUnlock(&gMDNSRecord
);
1284 HostDescriptionChanged(mDNS
* const inMDNS
)
1286 DEBUG_UNUSED( inMDNS
);
1288 udsserver_handle_configchange();
1292 mDNSlocal
unsigned WINAPI
1293 udsSocketThread(LPVOID inParam
)
1295 Win32EventSource
* source
= (Win32EventSource
*) inParam
;
1296 DWORD threadID
= GetCurrentThreadId();
1301 bool locked
= false;
1304 waitCount
= source
->waitCount
;
1305 waitList
[0] = source
->waitList
[0];
1306 waitList
[1] = source
->waitList
[1];
1307 done
= (bool) (source
->flags
& EventSourceFinalized
);
1313 result
= WaitForMultipleObjects(waitCount
, waitList
, FALSE
, INFINITE
);
1315 mDNSPlatformLock(&gMDNSRecord
);
1318 // <rdar://problem/3838237>
1320 // Look up the source by the thread id. This will ensure that the
1321 // source is still extant. It could already have been deleted
1322 // by the processing thread.
1327 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1329 if (source
->threadID
== threadID
)
1335 EventSourceUnlock();
1345 if (result
== WAIT_OBJECT_0
)
1347 source
->callback(source
->context
);
1352 else if (result
== WAIT_OBJECT_0
+ 1)
1355 // this is a bit of a hack. we want to clean up the internal data structures
1356 // so we'll go in here and it will clean up for us
1358 shutdown(source
->sock
, 2);
1359 source
->callback(source
->context
);
1365 // Unexpected wait result.
1366 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1370 done
= (bool) (source
->flags
& EventSourceFinalized
);
1372 mDNSPlatformUnlock(&gMDNSRecord
);
1377 source
->flags
|= EventSourceFlagsThreadDone
;
1378 safeToClose
= !( source
->flags
& EventSourceFlagsNoClose
);
1379 EventSourceUnlock();
1383 EventSourceFinalize( source
);
1390 mDNSPlatformUnlock(&gMDNSRecord
);
1393 _endthreadex_compat( (unsigned) err
);
1394 return( (unsigned) err
);
1399 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
)
1401 Win32EventSource
* newSource
;
1405 newSource
= malloc(sizeof(Win32EventSource
));
1406 require_action( newSource
, exit
, err
= mStatus_NoMemoryErr
);
1407 memset(newSource
, 0, sizeof(Win32EventSource
));
1409 newSource
->flags
= 0;
1410 newSource
->sock
= (SOCKET
) fd
;
1411 newSource
->callback
= callback
;
1412 newSource
->context
= context
;
1414 newSource
->socketEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1415 err
= translate_errno( newSource
->socketEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1416 require_noerr( err
, exit
);
1418 newSource
->closeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1419 err
= translate_errno( newSource
->closeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1420 require_noerr( err
, exit
);
1422 err
= WSAEventSelect(newSource
->sock
, newSource
->socketEvent
, FD_ACCEPT
|FD_READ
|FD_CLOSE
);
1423 err
= translate_errno( err
== 0, errno_compat(), kNoResourcesErr
);
1424 require_noerr( err
, exit
);
1426 newSource
->waitCount
= 0;
1427 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->socketEvent
;
1428 newSource
->waitList
[ newSource
->waitCount
++ ] = newSource
->closeEvent
;
1435 // add the event source to the end of the list, while checking
1436 // to see if the list needs to be initialized
1438 if ( gEventSources
.LinkOffset
== 0)
1440 InitLinkedList( &gEventSources
, offsetof( Win32EventSource
, next
));
1443 AddToTail( &gEventSources
, newSource
);
1446 // no longer using the list
1448 EventSourceUnlock();
1450 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
1451 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
1452 // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
1453 newSource
->threadHandle
= (HANDLE
) _beginthreadex_compat( NULL
, 0, udsSocketThread
, newSource
, CREATE_SUSPENDED
, &newSource
->threadID
);
1454 err
= translate_errno( newSource
->threadHandle
, (mStatus
) GetLastError(), kUnknownErr
);
1455 require_noerr( err
, exit
);
1457 result
= ResumeThread( newSource
->threadHandle
);
1458 err
= translate_errno( result
!= (DWORD
) -1, errno_compat(), kNoResourcesErr
);
1459 require_noerr( err
, exit
);
1463 if (err
&& newSource
)
1465 EventSourceFinalize(newSource
);
1473 udsSupportRemoveFDFromEventLoop( SocketRef fd
) // Note: This also CLOSES the socket
1475 Win32EventSource
* source
;
1476 mStatus err
= mStatus_NoError
;
1479 // find the event source
1483 for (source
= gEventSources
.Head
; source
; source
= source
->next
)
1485 if (source
->sock
== (SOCKET
) fd
)
1492 // if we found him, finalize him
1496 EventSourceFinalize(source
);
1500 // done with the list
1502 EventSourceUnlock();
1510 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
1519 EventSourceFinalize(Win32EventSource
* source
)
1523 Win32EventSource
* inserted
;
1532 // Find the session in the list.
1537 for( inserted
= (Win32EventSource
*) gEventSources
.Head
; inserted
; inserted
= inserted
->next
)
1539 if( inserted
== source
)
1544 require_action( inserted
, exit
, err
= kNotFoundErr
);
1547 // note that we've had finalize called
1549 source
->flags
|= EventSourceFinalized
;
1551 // If we're being called from the same thread as the session (e.g. message callback is closing the session) then
1552 // we must defer the close until the thread is done because the thread is still using the session object.
1555 threadID
= GetCurrentThreadId();
1556 sameThread
= source
->threadHandle
&& ( threadID
== source
->threadID
);
1557 if( sameThread
&& !( source
->flags
& EventSourceFlagsThreadDone
) )
1559 source
->flags
&= ~EventSourceFlagsNoClose
;
1563 // If the thread we're not being called from the session thread, but the thread has already marked itself as
1564 // as done (e.g. session closed from something like a peer disconnect and at the same time the client also
1565 // tried to close) then we only want to continue with the close if the thread is not going to close itself.
1567 if( !sameThread
&& ( source
->flags
& EventSourceFlagsThreadDone
) && !( source
->flags
& EventSourceFlagsNoClose
) )
1572 // Signal a close so the thread exits.
1574 if( source
->closeEvent
)
1576 ok
= SetEvent( source
->closeEvent
);
1577 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1585 source
->flags
|= EventSourceFlagsNoClose
;
1587 // Remove the session from the list.
1588 RemoveFromList(&gEventSources
, source
);
1590 EventSourceUnlock();
1593 // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
1595 if( source
->threadHandle
&& ( threadID
!= source
->threadID
) )
1597 result
= WaitForSingleObject( source
->threadHandle
, 3 * 1000 );
1598 check_translated_errno( result
== WAIT_OBJECT_0
, (OSStatus
) GetLastError(), result
);
1601 // Release the thread.
1603 if( source
->threadHandle
)
1605 ok
= CloseHandle( source
->threadHandle
);
1606 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1607 source
->threadHandle
= NULL
;
1610 // Release the socket event.
1612 if( source
->socketEvent
)
1614 ok
= CloseHandle( source
->socketEvent
);
1615 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1616 source
->socketEvent
= NULL
;
1619 // Release the close event.
1621 if( source
->closeEvent
)
1623 ok
= CloseHandle( source
->closeEvent
);
1624 check_translated_errno( ok
, errno_compat(), kUnknownErr
);
1625 source
->closeEvent
= NULL
;
1628 // Release the memory used by the object.
1633 dlog( kDebugLevelNotice
, DEBUG_NAME
"session closed\n" );
1639 EventSourceUnlock();
1649 EnterCriticalSection(&gEventSourceLock
);
1656 LeaveCriticalSection(&gEventSourceLock
);
1660 //===========================================================================================================================
1662 //===========================================================================================================================
1665 HaveLLRoute(PMIB_IPFORWARDROW rowExtant
)
1667 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
1669 BOOL bOrder
= FALSE
;
1672 unsigned long int i
;
1675 // Find out how big our buffer needs to be.
1677 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
1678 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
1681 // Allocate the memory for the table
1683 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
1684 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
1687 // Now get the table.
1689 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
1690 require_noerr( err
, exit
);
1693 // Search for the row in the table we want.
1695 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
1697 if (pIpForwardTable
->table
[i
].dwForwardDest
== inet_addr(kLLNetworkAddr
))
1699 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
1707 if ( pIpForwardTable
!= NULL
)
1709 free(pIpForwardTable
);
1716 //===========================================================================================================================
1718 //===========================================================================================================================
1724 MIB_IPFORWARDROW rowExtant
;
1726 MIB_IPFORWARDROW row
;
1729 ZeroMemory(&row
, sizeof(row
));
1731 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
1732 require_noerr( err
, exit
);
1733 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
1734 row
.dwForwardIfIndex
= ifIndex
;
1735 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
1736 row
.dwForwardType
= 3;
1737 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1738 row
.dwForwardAge
= 0;
1739 row
.dwForwardPolicy
= 0;
1740 row
.dwForwardMetric1
= 30;
1741 row
.dwForwardMetric2
= (DWORD
) - 1;
1742 row
.dwForwardMetric3
= (DWORD
) - 1;
1743 row
.dwForwardMetric4
= (DWORD
) - 1;
1744 row
.dwForwardMetric5
= (DWORD
) - 1;
1749 // check to make sure we don't already have a route
1751 if (HaveLLRoute(&rowExtant
))
1754 // set the age to 0 so that we can do a memcmp.
1756 rowExtant
.dwForwardAge
= 0;
1759 // check to see if this route is the same as our route
1761 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
1764 // if it isn't then delete this entry
1766 DeleteIpForwardEntry(&rowExtant
);
1771 // else it is, so we don't want to create another route
1777 if (addRoute
&& row
.dwForwardNextHop
)
1779 err
= CreateIpForwardEntry(&row
);
1781 require_noerr( err
, exit
);
1785 // see if this address is a link local address
1787 if ((row
.dwForwardNextHop
& 0xFFFF) == row
.dwForwardDest
)
1790 // if so, set up a route to ARP everything
1792 row
.dwForwardDest
= 0;
1793 row
.dwForwardIfIndex
= ifIndex
;
1794 row
.dwForwardMask
= 0;
1795 row
.dwForwardType
= 3;
1796 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
1797 row
.dwForwardAge
= 0;
1798 row
.dwForwardPolicy
= 0;
1799 row
.dwForwardMetric1
= 1;
1800 row
.dwForwardMetric2
= (DWORD
) - 1;
1801 row
.dwForwardMetric3
= (DWORD
) - 1;
1802 row
.dwForwardMetric4
= (DWORD
) - 1;
1803 row
.dwForwardMetric5
= (DWORD
) - 1;
1805 err
= CreateIpForwardEntry(&row
);
1807 require_noerr( err
, exit
);
1815 //===========================================================================================================================
1816 // GetRouteDestination
1817 //===========================================================================================================================
1820 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
1823 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
1824 IP_ADAPTER_INFO
* pAdapter
= NULL
;
1829 // GetBestInterface will fail if there is no default gateway
1830 // configured. If that happens, we will just take the first
1831 // interface in the list. MSDN support says there is no surefire
1832 // way to manually determine what the best interface might
1833 // be for a particular network address.
1835 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
1836 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
1844 // Make an initial call to GetAdaptersInfo to get
1845 // the necessary size into the bufLen variable
1847 err
= GetAdaptersInfo( NULL
, &bufLen
);
1848 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
1850 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
1851 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
1853 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
1854 require_noerr( err
, exit
);
1856 pAdapter
= pAdapterInfo
;
1859 // <rdar://problem/3718122>
1861 // Look for the Nortel VPN virtual interface. This interface
1862 // is identified by it's unique MAC address: 44-45-53-54-42-00
1864 // If the interface is active (i.e., has a non-zero IP Address),
1865 // then we want to disable routing table modifications.
1869 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
1870 (pAdapter
->AddressLength
== 6) &&
1871 (pAdapter
->Address
[0] == 0x44) &&
1872 (pAdapter
->Address
[1] == 0x45) &&
1873 (pAdapter
->Address
[2] == 0x53) &&
1874 (pAdapter
->Address
[3] == 0x54) &&
1875 (pAdapter
->Address
[4] == 0x42) &&
1876 (pAdapter
->Address
[5] == 0x00) &&
1877 (inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0))
1882 pAdapter
= pAdapter
->Next
;
1885 pAdapter
= pAdapterInfo
;
1891 // if we don't have an interface selected, choose the first one
1893 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
1895 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
1896 *ifIndex
= pAdapter
->Index
;
1901 pAdapter
= pAdapter
->Next
;
1906 if ( pAdapterInfo
!= NULL
)
1908 free( pAdapterInfo
);