1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
25 #include "CommonServices.h"
26 #include "DebugServices.h"
29 #include "uds_daemon.h"
30 #include "GenLinkedList.h"
36 #include "mDNSEmbeddedAPI.h"
38 #include "mDNSWin32.h"
42 #if( !TARGET_OS_WINDOWS_CE )
54 #ifndef HeapEnableTerminationOnCorruption
55 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
59 #pragma mark == Constants ==
62 //===========================================================================================================================
64 //===========================================================================================================================
66 #define DEBUG_NAME "[mDNSWin32] "
67 #define kServiceFirewallName L"Bonjour"
68 #define kServiceDependencies TEXT("Tcpip\0\0")
69 #define kDNSServiceCacheEntryCountDefault 512
70 #define kRetryFirewallPeriod 30 * 1000
71 #define kDefValueSize MAX_PATH + 1
73 #define kDefaultRouteMetric 399
74 #define kSecondsTo100NSUnits ( 10 * 1000 * 1000 )
75 #define kSPSMaintenanceWakePeriod -30
77 #define RR_CACHE_SIZE 500
78 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
80 #pragma mark == Structures ==
83 //===========================================================================================================================
85 //===========================================================================================================================
87 typedef struct EventSource
91 RegisterWaitableEventHandler handler
;
92 struct EventSource
* next
;
95 static BOOL gEventSourceListChanged
= FALSE
;
96 static EventSource
* gEventSourceList
= NULL
;
97 static EventSource
* gCurrentSource
= NULL
;
98 static int gEventSources
= 0;
100 #define kWaitListStopEvent ( WAIT_OBJECT_0 + 0 )
101 #define kWaitListInterfaceListChangedEvent ( WAIT_OBJECT_0 + 1 )
102 #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 2 )
103 #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 3 )
104 #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 4 )
105 #define kWaitListFileShareEvent ( WAIT_OBJECT_0 + 5 )
106 #define kWaitListFirewallEvent ( WAIT_OBJECT_0 + 6 )
107 #define kWaitListAdvertisedServicesEvent ( WAIT_OBJECT_0 + 7 )
108 #define kWaitListSPSWakeupEvent ( WAIT_OBJECT_0 + 8 )
109 #define kWaitListSPSSleepEvent ( WAIT_OBJECT_0 + 9 )
110 #define kWaitListFixedItemCount 10
114 #pragma mark == Prototypes ==
117 //===========================================================================================================================
119 //===========================================================================================================================
120 static void Usage( void );
121 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
122 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
123 static OSStatus
RemoveService( LPCTSTR inName
);
124 static OSStatus
SetServiceParameters();
125 static OSStatus
GetServiceParameters();
126 static OSStatus
CheckFirewall();
127 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
128 static void ReportStatus( int inType
, const char *inFormat
, ... );
130 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
131 static OSStatus
ServiceSetupEventLogging( void );
132 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
134 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
135 static void ServiceStop( void );
137 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
138 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
139 static OSStatus
ServiceSpecificStop( void );
140 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
141 static mStatus
SetupNotifications();
142 static mStatus
TearDownNotifications();
143 static mStatus
RegisterWaitableEvent( mDNS
* const inMDNS
, HANDLE event
, void * context
, RegisterWaitableEventHandler handler
);
144 static void UnregisterWaitableEvent( mDNS
* const inMDNS
, HANDLE event
);
145 static mStatus
SetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
);
146 static void UDSCanAccept( mDNS
* const inMDNS
, HANDLE event
, void * context
);
147 static void UDSCanRead( TCPSocket
* sock
);
148 static void HandlePowerSuspend( void * v
);
149 static void HandlePowerResumeSuspend( void * v
);
150 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
151 static mDNSu8
SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
);
152 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
153 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
154 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
);
155 static bool IsValidAddress( const char * addr
);
156 static bool IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
);
157 static bool IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
);
158 static bool IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
);
159 static const char * strnistr( const char * string
, const char * subString
, size_t max
);
162 # define StrLen(X) wcslen(X)
163 # define StrCmp(X,Y) wcscmp(X,Y)
165 # define StrLen(X) strlen(X)
166 # define StrCmp(X,Y) strcmp(X,Y)
170 #define kLLNetworkAddr "169.254.0.0"
171 #define kLLNetworkAddrMask "255.255.0.0"
174 #include "mDNSEmbeddedAPI.h"
177 #pragma mark == Globals ==
180 //===========================================================================================================================
182 //===========================================================================================================================
183 #define gMDNSRecord mDNSStorage
184 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
185 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
186 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
188 { kServiceName
, ServiceMain
},
191 DEBUG_LOCAL SOCKET gInterfaceListChangedSocket
= INVALID_SOCKET
;
192 DEBUG_LOCAL HANDLE gInterfaceListChangedEvent
= NULL
;
193 DEBUG_LOCAL HKEY gDescKey
= NULL
;
194 DEBUG_LOCAL HANDLE gDescChangedEvent
= NULL
; // Computer description changed event
195 DEBUG_LOCAL HKEY gTcpipKey
= NULL
;
196 DEBUG_LOCAL HANDLE gTcpipChangedEvent
= NULL
; // TCP/IP config changed
197 DEBUG_LOCAL HKEY gDdnsKey
= NULL
;
198 DEBUG_LOCAL HANDLE gDdnsChangedEvent
= NULL
; // DynDNS config changed
199 DEBUG_LOCAL HKEY gFileSharingKey
= NULL
;
200 DEBUG_LOCAL HANDLE gFileSharingChangedEvent
= NULL
; // File Sharing changed
201 DEBUG_LOCAL HKEY gFirewallKey
= NULL
;
202 DEBUG_LOCAL HANDLE gFirewallChangedEvent
= NULL
; // Firewall changed
203 DEBUG_LOCAL HKEY gAdvertisedServicesKey
= NULL
;
204 DEBUG_LOCAL HANDLE gAdvertisedServicesChangedEvent
= NULL
; // Advertised services changed
205 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
206 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
207 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
208 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
209 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
210 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
211 DEBUG_LOCAL
int gWaitCount
= 0;
212 DEBUG_LOCAL HANDLE
* gWaitList
= NULL
;
213 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
214 DEBUG_LOCAL HANDLE gSPSWakeupEvent
= NULL
;
215 DEBUG_LOCAL HANDLE gSPSSleepEvent
= NULL
;
216 DEBUG_LOCAL HANDLE gUDSEvent
= NULL
;
217 DEBUG_LOCAL SocketRef gUDSSocket
= 0;
218 DEBUG_LOCAL udsEventCallback gUDSCallback
= NULL
;
219 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
220 DEBUG_LOCAL DWORD gOSMajorVersion
;
221 DEBUG_LOCAL DWORD gOSMinorVersion
;
223 typedef DWORD ( WINAPI
* GetIpInterfaceEntryFunctionPtr
)( PMIB_IPINTERFACE_ROW
);
224 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
225 mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr
= NULL
;
232 //===========================================================================================================================
234 //===========================================================================================================================
235 int Main( int argc
, LPTSTR argv
[] )
242 HeapSetInformation( NULL
, HeapEnableTerminationOnCorruption
, NULL
, 0 );
244 debug_initialize( kDebugOutputTypeMetaConsole
);
245 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
247 // Default to automatically starting the service dispatcher if no extra arguments are specified.
249 start
= ( argc
<= 1 );
253 for( i
= 1; i
< argc
; ++i
)
255 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
260 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
261 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
264 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
268 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
270 err
= RemoveService( kServiceName
);
273 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
277 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
281 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
283 err
= RunDirect( argc
, argv
);
286 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
290 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
292 gServiceQuietMode
= !gServiceQuietMode
;
294 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
295 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
309 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
310 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
311 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
315 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
316 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
319 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
326 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
327 _CrtDumpMemoryLeaks();
331 //===========================================================================================================================
333 //===========================================================================================================================
335 static void Usage( void )
337 fprintf( stderr
, "\n" );
338 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
339 fprintf( stderr
, "\n" );
340 fprintf( stderr
, " <no args> Runs the service normally\n" );
341 fprintf( stderr
, " -install Creates the service and starts it\n" );
342 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
343 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
344 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
345 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
346 fprintf( stderr
, " -remote Allow remote connections\n" );
347 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
348 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
349 fprintf( stderr
, "\n" );
352 //===========================================================================================================================
353 // ConsoleControlHandler
354 //===========================================================================================================================
356 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
362 switch( inControlEvent
)
365 case CTRL_BREAK_EVENT
:
366 case CTRL_CLOSE_EVENT
:
367 case CTRL_LOGOFF_EVENT
:
368 case CTRL_SHUTDOWN_EVENT
:
369 err
= ServiceSpecificStop();
370 require_noerr( err
, exit
);
383 //===========================================================================================================================
385 //===========================================================================================================================
387 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
393 TCHAR fullPath
[ MAX_PATH
];
400 // Get a full path to the executable since a relative path may have been specified.
402 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
403 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
404 require_noerr( err
, exit
);
406 // Create the service and start it.
408 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
409 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
410 require_noerr( err
, exit
);
412 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
413 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
415 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
416 require_noerr( err
, exit
);
418 err
= SetServiceParameters();
423 err
= SetServiceInfo( scm
, inName
, inDescription
);
427 ok
= StartService( service
, 0, NULL
);
428 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
429 require_noerr( err
, exit
);
431 ReportStatus( EVENTLOG_SUCCESS
, "installed service\n" );
437 CloseServiceHandle( service
);
441 CloseServiceHandle( scm
);
446 //===========================================================================================================================
448 //===========================================================================================================================
450 static OSStatus
RemoveService( LPCTSTR inName
)
456 SERVICE_STATUS status
;
461 // Open a connection to the service.
463 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
464 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
465 require_noerr( err
, exit
);
467 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
468 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
469 require_noerr( err
, exit
);
471 // Stop the service, if it is not already stopped, then delete it.
473 ok
= QueryServiceStatus( service
, &status
);
474 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
475 require_noerr( err
, exit
);
477 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
479 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
480 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
483 ok
= DeleteService( service
);
484 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
485 require_noerr( err
, exit
);
487 ReportStatus( EVENTLOG_SUCCESS
, "Removed service\n" );
493 CloseServiceHandle( service
);
497 CloseServiceHandle( scm
);
504 //===========================================================================================================================
505 // SetServiceParameters
506 //===========================================================================================================================
508 static OSStatus
SetServiceParameters()
511 DWORD valueLen
= sizeof(DWORD
);
519 // Add/Open Parameters section under service entry in registry
521 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
522 require_noerr( err
, exit
);
525 // If the value isn't already there, then we create it
527 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
529 if (err
!= ERROR_SUCCESS
)
533 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
534 require_noerr( err
, exit
);
549 //===========================================================================================================================
550 // GetServiceParameters
551 //===========================================================================================================================
553 static OSStatus
GetServiceParameters()
564 // Add/Open Parameters section under service entry in registry
566 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
567 require_noerr( err
, exit
);
569 valueLen
= sizeof(DWORD
);
570 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
571 if (err
== ERROR_SUCCESS
)
573 gServiceManageLLRouting
= (value
) ? true : false;
576 valueLen
= sizeof(DWORD
);
577 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
578 if (err
== ERROR_SUCCESS
)
580 gServiceCacheEntryCount
= value
;
594 //===========================================================================================================================
596 //===========================================================================================================================
598 static OSStatus
CheckFirewall()
603 ENUM_SERVICE_STATUS
* lpService
= NULL
;
607 DWORD bytesNeeded
= 0;
609 DWORD resumeHandle
= 0;
614 BOOL isRunning
= FALSE
;
615 OSStatus err
= kUnknownErr
;
617 // Check to see if the firewall service is running. If it isn't, then
618 // we want to return immediately
620 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
621 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
622 require_noerr( err
, exit
);
624 srvType
= SERVICE_WIN32
;
625 srvState
= SERVICE_STATE_ALL
;
629 // Call EnumServicesStatus using the handle returned by OpenSCManager
631 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
633 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
643 dwBytes
= bytesNeeded
;
645 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
646 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
649 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
650 require_noerr( err
, exit
);
652 for ( i
= 0; i
< srvCount
; i
++ )
654 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
656 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
665 require_action( isRunning
, exit
, err
= kUnknownErr
);
667 // Check to see if we've managed the firewall.
668 // This package might have been installed, then
669 // the OS was upgraded to SP2 or above. If that's
670 // the case, then we need to manipulate the firewall
671 // so networking works correctly.
673 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
674 require_noerr( err
, exit
);
676 valueLen
= sizeof(DWORD
);
677 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
679 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
681 wchar_t fullPath
[ MAX_PATH
];
684 // Get a full path to the executable
686 size
= GetModuleFileNameW( NULL
, fullPath
, MAX_PATH
);
687 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
688 require_noerr( err
, exit
);
690 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
691 require_noerr( err
, exit
);
694 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
695 require_noerr( err
, exit
);
712 CloseServiceHandle ( sc
);
720 //===========================================================================================================================
722 //===========================================================================================================================
724 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
729 SERVICE_DESCRIPTION description
;
730 SERVICE_FAILURE_ACTIONS actions
;
734 check( inServiceName
);
735 check( inDescription
);
740 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
744 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
745 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
746 require_noerr( err
, exit
);
749 lock
= LockServiceDatabase( inSCM
);
750 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
751 require_noerr( err
, exit
);
753 // Open a handle to the service.
755 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
756 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
757 require_noerr( err
, exit
);
759 // Change the description.
761 description
.lpDescription
= (LPTSTR
) inDescription
;
762 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
763 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
764 require_noerr( err
, exit
);
766 actions
.dwResetPeriod
= INFINITE
;
767 actions
.lpRebootMsg
= NULL
;
768 actions
.lpCommand
= NULL
;
769 actions
.cActions
= 1;
770 actions
.lpsaActions
= &action
;
772 action
.Type
= SC_ACTION_RESTART
;
774 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
775 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
776 require_noerr( err
, exit
);
781 // Close the service and release the lock.
785 CloseServiceHandle( service
);
789 UnlockServiceDatabase( lock
);
794 //===========================================================================================================================
796 //===========================================================================================================================
798 static void ReportStatus( int inType
, const char *inFormat
, ... )
800 if( !gServiceQuietMode
)
804 va_start( args
, inFormat
);
805 if( gServiceEventSource
)
809 const char * array
[ 1 ];
811 vsprintf( s
, inFormat
, args
);
813 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, MDNSRESPONDER_LOG
, NULL
, 1, 0, array
, NULL
);
814 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
820 n
= vfprintf( stderr
, inFormat
, args
);
827 //===========================================================================================================================
829 //===========================================================================================================================
831 int RunDirect( int argc
, LPTSTR argv
[] )
839 // Install a Console Control Handler to handle things like control-c signals.
841 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
842 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
843 require_noerr( err
, exit
);
845 err
= ServiceSpecificInitialize( argc
, argv
);
846 require_noerr( err
, exit
);
849 // Run the service. This does not return until the service quits or is stopped.
851 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Running service directly\n" );
853 err
= ServiceSpecificRun( argc
, argv
);
854 require_noerr( err
, exit
);
861 ServiceSpecificFinalize( argc
, argv
);
870 //===========================================================================================================================
872 //===========================================================================================================================
874 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
879 err
= ServiceSetupEventLogging();
882 err
= GetServiceParameters();
885 // Initialize the service status and register the service control handler with the name of the service.
887 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
888 gServiceStatus
.dwCurrentState
= 0;
889 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_SHUTDOWN
|SERVICE_ACCEPT_POWEREVENT
;
890 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
891 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
892 gServiceStatus
.dwCheckPoint
= 0;
893 gServiceStatus
.dwWaitHint
= 0;
895 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
896 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
897 require_noerr( err
, exit
);
899 // Mark the service as starting.
901 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
902 gServiceStatus
.dwCheckPoint
= 0;
903 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
904 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
905 check_translated_errno( ok
, GetLastError(), kParamErr
);
907 // Run the service. This does not return until the service quits or is stopped.
909 err
= ServiceRun( (int) argc
, argv
);
912 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
913 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
916 // Service-specific work is done so mark the service as stopped.
918 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
919 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
920 check_translated_errno( ok
, GetLastError(), kParamErr
);
922 // Note: The service status handle should not be closed according to Microsoft documentation.
925 if( gServiceEventSource
)
927 ok
= DeregisterEventSource( gServiceEventSource
);
928 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
929 gServiceEventSource
= NULL
;
933 //===========================================================================================================================
934 // ServiceSetupEventLogging
935 //===========================================================================================================================
937 static OSStatus
ServiceSetupEventLogging( void )
942 DWORD typesSupported
;
943 TCHAR path
[ MAX_PATH
];
948 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
950 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
951 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
952 require_noerr( err
, exit
);
954 // Add the name to the EventMessageFile subkey.
957 GetModuleFileName( NULL
, path
, MAX_PATH
);
958 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
959 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
960 require_noerr( err
, exit
);
962 // Set the supported event types in the TypesSupported subkey.
966 | EVENTLOG_ERROR_TYPE
967 | EVENTLOG_WARNING_TYPE
968 | EVENTLOG_INFORMATION_TYPE
969 | EVENTLOG_AUDIT_SUCCESS
970 | EVENTLOG_AUDIT_FAILURE
;
971 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
972 require_noerr( err
, exit
);
974 // Set up the event source.
976 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
977 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
978 require_noerr( err
, exit
);
988 //===========================================================================================================================
989 // HandlePowerSuspend
990 //===========================================================================================================================
992 static void HandlePowerSuspend( void * v
)
994 LARGE_INTEGER timeout
;
999 dlog( kDebugLevelInfo
, DEBUG_NAME
"HandlePowerSuspend\n" );
1001 gMDNSRecord
.SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess( &timeout
);
1003 if ( gMDNSRecord
.SystemWakeOnLANEnabled
)
1005 ok
= SetWaitableTimer( gSPSWakeupEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1009 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1013 //===========================================================================================================================
1014 // HandlePowerResumeSuspend
1015 //===========================================================================================================================
1017 static void HandlePowerResumeSuspend( void * v
)
1021 dlog( kDebugLevelInfo
, DEBUG_NAME
"HandlePowerResumeSuspend\n" );
1023 if ( gSPSWakeupEvent
)
1025 CancelWaitableTimer( gSPSWakeupEvent
);
1028 if ( gSPSSleepEvent
)
1030 CancelWaitableTimer( gSPSSleepEvent
);
1033 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1037 //===========================================================================================================================
1038 // ServiceControlHandler
1039 //===========================================================================================================================
1041 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
1046 DEBUG_UNUSED( inEventData
);
1047 DEBUG_UNUSED( inContext
);
1052 case SERVICE_CONTROL_STOP
:
1053 case SERVICE_CONTROL_SHUTDOWN
:
1054 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
1060 case SERVICE_CONTROL_POWEREVENT
:
1062 if (inEventType
== PBT_APMSUSPEND
)
1064 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: PBT_APMSUSPEND\n" );
1066 QueueUserAPC( ( PAPCFUNC
) HandlePowerSuspend
, gMDNSRecord
.p
->mainThread
, ( ULONG_PTR
) NULL
);
1068 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1070 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1072 QueueUserAPC( ( PAPCFUNC
) HandlePowerResumeSuspend
, gMDNSRecord
.p
->mainThread
, ( ULONG_PTR
) NULL
);
1078 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1082 if( setStatus
&& gServiceStatusHandle
)
1084 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1085 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1091 //===========================================================================================================================
1093 //===========================================================================================================================
1095 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1101 DEBUG_UNUSED( argc
);
1102 DEBUG_UNUSED( argv
);
1104 initialized
= FALSE
;
1106 // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1107 // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1108 // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1109 // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1110 // any installers that are waiting for our state to change.
1112 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1113 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1114 check_translated_errno( ok
, GetLastError(), kParamErr
);
1116 // Initialize the service-specific stuff
1118 err
= ServiceSpecificInitialize( argc
, argv
);
1119 require_noerr( err
, exit
);
1122 err
= CheckFirewall();
1127 gRetryFirewall
= TRUE
;
1130 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1132 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service started\n" );
1133 err
= ServiceSpecificRun( argc
, argv
);
1134 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service stopped (%d)\n", err
);
1135 require_noerr( err
, exit
);
1137 // Service stopped. Clean up and we're done.
1142 ServiceSpecificFinalize( argc
, argv
);
1147 //===========================================================================================================================
1149 //===========================================================================================================================
1151 static void ServiceStop( void )
1156 // Signal the event to cause the service to exit.
1158 if( gServiceStatusHandle
)
1160 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1161 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1162 check_translated_errno( ok
, GetLastError(), kParamErr
);
1165 err
= ServiceSpecificStop();
1171 #pragma mark == Service Specific ==
1174 //===========================================================================================================================
1175 // ServiceSpecificInitialize
1176 //===========================================================================================================================
1178 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1180 OSVERSIONINFO osInfo
;
1184 DEBUG_UNUSED( argc
);
1185 DEBUG_UNUSED( argv
);
1187 mDNSPlatformMemZero( &gMDNSRecord
, sizeof gMDNSRecord
);
1188 mDNSPlatformMemZero( &gPlatformStorage
, sizeof gPlatformStorage
);
1190 gPlatformStorage
.registerWaitableEventFunc
= RegisterWaitableEvent
;
1191 gPlatformStorage
.unregisterWaitableEventFunc
= UnregisterWaitableEvent
;
1192 gPlatformStorage
.reportStatusFunc
= ReportStatus
;
1194 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1195 require_noerr( err
, exit
);
1197 err
= SetupNotifications();
1200 err
= udsserver_init(mDNSNULL
, 0);
1201 require_noerr( err
, exit
);
1204 // Get the version of Windows that we're running on
1206 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
1207 ok
= GetVersionEx( &osInfo
);
1208 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1209 require_noerr( err
, exit
);
1210 gOSMajorVersion
= osInfo
.dwMajorVersion
;
1211 gOSMinorVersion
= osInfo
.dwMinorVersion
;
1213 SetLLRoute( &gMDNSRecord
);
1218 ServiceSpecificFinalize( argc
, argv
);
1223 //===========================================================================================================================
1224 // ServiceSpecificRun
1225 //===========================================================================================================================
1227 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1236 DEBUG_UNUSED( argc
);
1237 DEBUG_UNUSED( argv
);
1239 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1241 err
= SetupInterfaceList( &gMDNSRecord
);
1244 err
= uDNS_SetupDNSConfig( &gMDNSRecord
);
1256 err
= SetupWaitList( &gMDNSRecord
, &waitList
, &waitListCount
);
1257 require_noerr( err
, exit
);
1259 gEventSourceListChanged
= FALSE
;
1261 while ( !gEventSourceListChanged
)
1263 static mDNSs32 RepeatedBusy
= 0;
1264 mDNSs32 nextTimerEvent
;
1266 // Give the mDNS core a chance to do its work and determine next event time.
1268 nextTimerEvent
= udsserver_idle( mDNS_Execute( &gMDNSRecord
) - mDNS_TimeNow( &gMDNSRecord
) );
1270 if ( nextTimerEvent
< 0) nextTimerEvent
= 0;
1271 else if ( nextTimerEvent
> (0x7FFFFFFF / 1000)) nextTimerEvent
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
1272 else nextTimerEvent
= ( nextTimerEvent
* 1000) / mDNSPlatformOneSecond
;
1274 // Debugging sanity check, to guard against CPU spins
1276 if ( nextTimerEvent
> 0 )
1284 if ( ++RepeatedBusy
>= mDNSPlatformOneSecond
)
1286 ShowTaskSchedulingError( &gMDNSRecord
);
1291 if ( gMDNSRecord
.ShutdownTime
)
1293 mDNSs32 now
= mDNS_TimeNow( &gMDNSRecord
);
1295 if ( mDNS_ExitNow( &gMDNSRecord
, now
) )
1297 mDNS_FinalExit( &gMDNSRecord
);
1302 if ( nextTimerEvent
- gMDNSRecord
.ShutdownTime
>= 0 )
1304 nextTimerEvent
= gMDNSRecord
.ShutdownTime
;
1308 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1310 // Note: There seems to be a bug in WinSock with respect to Alertable I/O. According
1311 // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
1312 // callbacks will only be invoked during the following calls (when the caller sets
1313 // the appropriate flag):
1316 // - WaitForSingleObjectEx
1317 // - WaitForMultipleObjectsEx
1318 // - SignalObjectAndWait
1319 // - MsgWaitForMultipleObjectsEx
1321 // However, we have seen callbacks be invoked during calls to bind() (and maybe others). If there
1322 // weren't a bug, then socket events would only be queued during the call to WaitForMultipleObjects() and
1323 // we'd only have to check them once afterwards. However since that doesn't seem to be the case, we'll
1324 // check the queue both before we call WaitForMultipleObjects() and after.
1326 DispatchSocketEvents( &gMDNSRecord
);
1327 result
= WaitForMultipleObjectsEx( ( DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) nextTimerEvent
, TRUE
);
1328 check( result
!= WAIT_FAILED
);
1329 DispatchSocketEvents( &gMDNSRecord
);
1331 if ( result
!= WAIT_FAILED
)
1333 if ( result
== WAIT_TIMEOUT
)
1335 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1337 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
1340 else if ( result
== WAIT_IO_COMPLETION
)
1342 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"i/o completion\n" );
1345 else if ( result
== kWaitListStopEvent
)
1347 // Stop event. Set the done flag and break to exit.
1349 dlog( kDebugLevelVerbose
, DEBUG_NAME
"stopping...\n" );
1351 mDNS_StartExit( &gMDNSRecord
);
1354 else if( result
== kWaitListInterfaceListChangedEvent
)
1360 // It would be nice to come up with a more elegant solution to this, but it seems that
1361 // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as
1362 // as a simple workaround, we'll pause for a couple of seconds before processing the change.
1364 // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1365 // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another
1366 // second on top of that to account for machine load or some other exigency.
1370 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1372 InterfaceListDidChange( &gMDNSRecord
);
1374 // reset the event handler
1377 err
= WSAIoctl( gInterfaceListChangedSocket
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1380 check( errno_compat() == WSAEWOULDBLOCK
);
1383 else if ( result
== kWaitListComputerDescriptionEvent
)
1385 // The computer description might have changed
1387 ComputerDescriptionDidChange( &gMDNSRecord
);
1388 udsserver_handle_configchange( &gMDNSRecord
);
1390 // and reset the event handler
1391 if ( ( gDescKey
!= NULL
) && ( gDescChangedEvent
!= NULL
) )
1393 err
= RegNotifyChangeKeyValue( gDescKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, gDescChangedEvent
, TRUE
);
1397 else if ( result
== kWaitListTCPIPEvent
)
1399 // The TCP/IP might have changed
1401 TCPIPConfigDidChange( &gMDNSRecord
);
1402 udsserver_handle_configchange( &gMDNSRecord
);
1404 // and reset the event handler
1406 if ( ( gTcpipKey
!= NULL
) && ( gTcpipChangedEvent
) )
1408 err
= RegNotifyChangeKeyValue( gTcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gTcpipChangedEvent
, TRUE
);
1412 else if ( result
== kWaitListDynDNSEvent
)
1414 // The DynDNS config might have changed
1416 DynDNSConfigDidChange( &gMDNSRecord
);
1417 udsserver_handle_configchange( &gMDNSRecord
);
1419 // and reset the event handler
1421 if ((gDdnsKey
!= NULL
) && (gDdnsChangedEvent
))
1423 err
= RegNotifyChangeKeyValue(gDdnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gDdnsChangedEvent
, TRUE
);
1427 else if ( result
== kWaitListFileShareEvent
)
1429 // File sharing changed
1431 FileSharingDidChange( &gMDNSRecord
);
1433 // and reset the event handler
1435 if ((gFileSharingKey
!= NULL
) && (gFileSharingChangedEvent
))
1437 err
= RegNotifyChangeKeyValue(gFileSharingKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFileSharingChangedEvent
, TRUE
);
1441 else if ( result
== kWaitListFirewallEvent
)
1443 // Firewall configuration changed
1445 FirewallDidChange( &gMDNSRecord
);
1447 // and reset the event handler
1449 if ((gFirewallKey
!= NULL
) && (gFirewallChangedEvent
))
1451 err
= RegNotifyChangeKeyValue(gFirewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFirewallChangedEvent
, TRUE
);
1455 else if ( result
== kWaitListAdvertisedServicesEvent
)
1457 // Ultimately we'll want to manage multiple services, but right now the only service
1458 // we'll be managing is SMB.
1460 FileSharingDidChange( &gMDNSRecord
);
1462 // and reset the event handler
1464 if ( ( gAdvertisedServicesKey
!= NULL
) && ( gAdvertisedServicesChangedEvent
) )
1466 err
= RegNotifyChangeKeyValue(gAdvertisedServicesKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gAdvertisedServicesChangedEvent
, TRUE
);
1470 else if ( result
== kWaitListSPSWakeupEvent
)
1472 LARGE_INTEGER timeout
;
1474 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Maintenance wake" );
1476 timeout
.QuadPart
= kSPSMaintenanceWakePeriod
;
1477 timeout
.QuadPart
*= kSecondsTo100NSUnits
;
1479 SetWaitableTimer( gSPSSleepEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1481 else if ( result
== kWaitListSPSSleepEvent
)
1483 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Returning to sleep after maintenance wake" );
1485 // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
1486 // call HandlePowerSuspend() explicity. This will reset the
1487 // maintenance wake timers.
1489 HandlePowerSuspend( NULL
);
1490 SetSuspendState( FALSE
, FALSE
, FALSE
);
1496 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
1497 dlog( kDebugLevelChatty
, DEBUG_NAME
"waitable event on %d\n", waitItemIndex
);
1498 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
1500 if ( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
1502 HANDLE signaledEvent
;
1505 signaledEvent
= waitList
[ waitItemIndex
];
1507 // If gCurrentSource is not NULL, then this routine has been called
1508 // re-entrantly which should never happen.
1510 check( !gCurrentSource
);
1512 for ( gCurrentSource
= gEventSourceList
; gCurrentSource
; )
1514 EventSource
* current
= gCurrentSource
;
1516 if ( gCurrentSource
->event
== signaledEvent
)
1518 gCurrentSource
->handler( &gMDNSRecord
, gCurrentSource
->event
, gCurrentSource
->context
);
1523 // If the current node was removed as a result of calling
1524 // the handler, then gCurrentSource was already incremented to
1525 // the next node. If it wasn't removed, then increment it
1528 if ( gCurrentSource
== current
)
1530 gCurrentSource
= gCurrentSource
->next
;
1534 gCurrentSource
= NULL
;
1540 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1548 err
= SetupInterfaceList( &gMDNSRecord
);
1551 err
= uDNS_SetupDNSConfig( &gMDNSRecord
);
1571 //===========================================================================================================================
1572 // ServiceSpecificStop
1573 //===========================================================================================================================
1575 static OSStatus
ServiceSpecificStop( void )
1580 ok
= SetEvent(gStopEvent
);
1581 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1582 require_noerr( err
, exit
);
1587 //===========================================================================================================================
1588 // ServiceSpecificFinalize
1589 //===========================================================================================================================
1591 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1593 DEBUG_UNUSED( argc
);
1594 DEBUG_UNUSED( argv
);
1597 // clean up any open sessions
1599 while ( gEventSourceList
)
1601 UnregisterWaitableEvent( &gMDNSRecord
, gEventSourceList
->event
);
1605 // clean up the notifications
1607 TearDownNotifications();
1610 // clean up loaded library
1613 if( gIPHelperLibraryInstance
)
1615 gGetIpInterfaceEntryFunctionPtr
= NULL
;
1617 FreeLibrary( gIPHelperLibraryInstance
);
1618 gIPHelperLibraryInstance
= NULL
;
1623 //===========================================================================================================================
1624 // SetupNotifications
1625 //===========================================================================================================================
1627 mDNSlocal mStatus
SetupNotifications()
1631 unsigned long param
;
1636 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1637 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1638 require_noerr( err
, exit
);
1640 // Register to listen for address list changes.
1642 gInterfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1643 err
= translate_errno( gInterfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1644 require_noerr( err
, exit
);
1646 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1647 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
1648 require_noerr( err
, exit
);
1649 gInterfaceListChangedSocket
= sock
;
1651 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1652 // when a change to the interface list is detected.
1655 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
1656 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
1657 require_noerr( err
, exit
);
1661 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1664 check( errno_compat() == WSAEWOULDBLOCK
);
1667 err
= WSAEventSelect( sock
, gInterfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
1668 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
1669 require_noerr( err
, exit
);
1671 gDescChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
1672 err
= translate_errno( gDescChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1673 require_noerr( err
, exit
);
1675 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ
, &gDescKey
);
1676 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
1678 if ( gDescKey
!= NULL
)
1680 err
= RegNotifyChangeKeyValue( gDescKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, gDescChangedEvent
, TRUE
);
1681 require_noerr( err
, exit
);
1684 // This will catch all changes to tcp/ip networking, including changes to the domain search list
1686 gTcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1687 err
= translate_errno( gTcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1688 require_noerr( err
, exit
);
1690 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey
);
1691 require_noerr( err
, exit
);
1693 err
= RegNotifyChangeKeyValue( gTcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gTcpipChangedEvent
, TRUE
);
1694 require_noerr( err
, exit
);
1696 // This will catch all changes to ddns configuration
1698 gDdnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1699 err
= translate_errno( gDdnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1700 require_noerr( err
, exit
);
1702 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &gDdnsKey
);
1703 require_noerr( err
, exit
);
1705 err
= RegNotifyChangeKeyValue( gDdnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gDdnsChangedEvent
, TRUE
);
1706 require_noerr( err
, exit
);
1708 // This will catch all changes to file sharing
1710 gFileSharingChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1711 err
= translate_errno( gFileSharingChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1712 require_noerr( err
, exit
);
1714 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey
);
1716 // Just to make sure that initialization doesn't fail on some old OS
1717 // that doesn't have this key, we'll only add the notification if
1722 err
= RegNotifyChangeKeyValue( gFileSharingKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFileSharingChangedEvent
, TRUE
);
1723 require_noerr( err
, exit
);
1727 err
= mStatus_NoError
;
1730 // This will catch changes to the Windows firewall
1732 gFirewallChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1733 err
= translate_errno( gFirewallChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1734 require_noerr( err
, exit
);
1736 // Just to make sure that initialization doesn't fail on some old OS
1737 // that doesn't have this key, we'll only add the notification if
1740 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey
);
1744 err
= RegNotifyChangeKeyValue( gFirewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFirewallChangedEvent
, TRUE
);
1745 require_noerr( err
, exit
);
1749 err
= mStatus_NoError
;
1752 // This will catch all changes to advertised services configuration
1754 gAdvertisedServicesChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1755 err
= translate_errno( gAdvertisedServicesChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1756 require_noerr( err
, exit
);
1758 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\Services"), &gAdvertisedServicesKey
);
1759 require_noerr( err
, exit
);
1761 err
= RegNotifyChangeKeyValue( gAdvertisedServicesKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gAdvertisedServicesChangedEvent
, TRUE
);
1762 require_noerr( err
, exit
);
1764 gSPSWakeupEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1765 err
= translate_errno( gSPSWakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1766 require_noerr( err
, exit
);
1768 gSPSSleepEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1769 err
= translate_errno( gSPSSleepEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1770 require_noerr( err
, exit
);
1772 gUDSEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1773 err
= translate_errno( gUDSEvent
, ( mStatus
) GetLastError(), kUnknownErr
);
1774 require_noerr( err
, exit
);
1779 TearDownNotifications();
1784 //===========================================================================================================================
1785 // TearDownNotifications
1786 //===========================================================================================================================
1788 mDNSlocal mStatus
TearDownNotifications()
1792 CloseHandle( gStopEvent
);
1796 if( IsValidSocket( gInterfaceListChangedSocket
) )
1798 close_compat( gInterfaceListChangedSocket
);
1799 gInterfaceListChangedSocket
= kInvalidSocketRef
;
1802 if( gInterfaceListChangedEvent
)
1804 CloseHandle( gInterfaceListChangedEvent
);
1805 gInterfaceListChangedEvent
= 0;
1808 if ( gDescChangedEvent
!= NULL
)
1810 CloseHandle( gDescChangedEvent
);
1811 gDescChangedEvent
= NULL
;
1814 if ( gDescKey
!= NULL
)
1816 RegCloseKey( gDescKey
);
1820 if ( gTcpipChangedEvent
!= NULL
)
1822 CloseHandle( gTcpipChangedEvent
);
1823 gTcpipChangedEvent
= NULL
;
1826 if ( gDdnsChangedEvent
!= NULL
)
1828 CloseHandle( gDdnsChangedEvent
);
1829 gDdnsChangedEvent
= NULL
;
1832 if ( gDdnsKey
!= NULL
)
1834 RegCloseKey( gDdnsKey
);
1838 if ( gFileSharingChangedEvent
!= NULL
)
1840 CloseHandle( gFileSharingChangedEvent
);
1841 gFileSharingChangedEvent
= NULL
;
1844 if ( gFileSharingKey
!= NULL
)
1846 RegCloseKey( gFileSharingKey
);
1847 gFileSharingKey
= NULL
;
1850 if ( gFirewallChangedEvent
!= NULL
)
1852 CloseHandle( gFirewallChangedEvent
);
1853 gFirewallChangedEvent
= NULL
;
1856 if ( gFirewallKey
!= NULL
)
1858 RegCloseKey( gFirewallKey
);
1859 gFirewallKey
= NULL
;
1862 if ( gAdvertisedServicesChangedEvent
!= NULL
)
1864 CloseHandle( gAdvertisedServicesChangedEvent
);
1865 gAdvertisedServicesChangedEvent
= NULL
;
1868 if ( gAdvertisedServicesKey
!= NULL
)
1870 RegCloseKey( gAdvertisedServicesKey
);
1871 gAdvertisedServicesKey
= NULL
;
1874 if ( gSPSWakeupEvent
)
1876 CloseHandle( gSPSWakeupEvent
);
1877 gSPSWakeupEvent
= NULL
;
1880 if ( gSPSSleepEvent
)
1882 CloseHandle( gSPSSleepEvent
);
1883 gSPSSleepEvent
= NULL
;
1886 return( mStatus_NoError
);
1890 //===========================================================================================================================
1891 // RegisterWaitableEvent
1892 //===========================================================================================================================
1894 static mStatus
RegisterWaitableEvent( mDNS
* const inMDNS
, HANDLE event
, void * context
, RegisterWaitableEventHandler handler
)
1896 EventSource
* source
;
1897 mStatus err
= mStatus_NoError
;
1903 source
= ( EventSource
* ) malloc( sizeof( EventSource
) );
1904 require_action( source
, exit
, err
= mStatus_NoMemoryErr
);
1905 mDNSPlatformMemZero( source
, sizeof( EventSource
) );
1906 source
->event
= event
;
1907 source
->context
= context
;
1908 source
->handler
= handler
;
1910 source
->next
= gEventSourceList
;
1911 gEventSourceList
= source
;
1912 gEventSourceListChanged
= TRUE
;
1921 //===========================================================================================================================
1922 // UnregisterWaitableEvent
1923 //===========================================================================================================================
1925 static void UnregisterWaitableEvent( mDNS
* const inMDNS
, HANDLE event
)
1927 EventSource
* current
= gEventSourceList
;
1928 EventSource
* last
= NULL
;
1935 if ( current
->event
== event
)
1939 gEventSourceList
= current
->next
;
1943 last
->next
= current
->next
;
1946 gEventSourceListChanged
= TRUE
;
1948 // Protect against removing the node that we happen
1949 // to be looking at as we iterate through the event
1950 // source list in ServiceSpecificRun()
1952 if ( current
== gCurrentSource
)
1954 gCurrentSource
= current
->next
;
1964 current
= current
->next
;
1969 //===========================================================================================================================
1971 //===========================================================================================================================
1973 mDNSlocal mStatus
SetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
1977 HANDLE
* waitItemPtr
;
1978 EventSource
* source
;
1981 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up wait list\n" );
1985 check( outWaitList
);
1986 check( outWaitListCount
);
1988 // Allocate an array to hold all the objects to wait on.
1990 waitListCount
= kWaitListFixedItemCount
+ gEventSources
;
1991 waitList
= ( HANDLE
* ) malloc( waitListCount
* sizeof( *waitList
) );
1992 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
1993 waitItemPtr
= waitList
;
1995 // Add the fixed wait items to the beginning of the list.
1997 *waitItemPtr
++ = gStopEvent
;
1998 *waitItemPtr
++ = gInterfaceListChangedEvent
;
1999 *waitItemPtr
++ = gDescChangedEvent
;
2000 *waitItemPtr
++ = gTcpipChangedEvent
;
2001 *waitItemPtr
++ = gDdnsChangedEvent
;
2002 *waitItemPtr
++ = gFileSharingChangedEvent
;
2003 *waitItemPtr
++ = gFirewallChangedEvent
;
2004 *waitItemPtr
++ = gAdvertisedServicesChangedEvent
;
2005 *waitItemPtr
++ = gSPSWakeupEvent
;
2006 *waitItemPtr
++ = gSPSSleepEvent
;
2008 for ( source
= gEventSourceList
; source
; source
= source
->next
)
2010 *waitItemPtr
++ = source
->event
;
2013 check( ( int )( waitItemPtr
- waitList
) == waitListCount
);
2015 *outWaitList
= waitList
;
2016 *outWaitListCount
= waitListCount
;
2018 err
= mStatus_NoError
;
2027 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up wait list done (err=%d %m)\n", err
, err
);
2032 //===========================================================================================================================
2034 //===========================================================================================================================
2037 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
2039 if (status
== mStatus_ConfigChanged
)
2041 SetLLRoute( inMDNS
);
2046 //===========================================================================================================================
2048 //===========================================================================================================================
2050 mDNSlocal
void UDSCanAccept( mDNS
* const inMDNS
, HANDLE event
, void * context
)
2057 gUDSCallback( ( int ) gUDSSocket
, 0, context
);
2062 //===========================================================================================================================
2064 //===========================================================================================================================
2066 mDNSlocal
void UDSCanRead( TCPSocket
* sock
)
2068 udsEventCallback callback
= ( udsEventCallback
) sock
->userCallback
;
2072 callback( (int) sock
->fd
, 0, sock
->userContext
);
2077 //===========================================================================================================================
2078 // udsSupportAddFDToEventLoop
2079 //===========================================================================================================================
2083 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
, void **platform_data
)
2085 mStatus err
= mStatus_NoError
;
2087 // We are using some knowledge of what is being passed to us here. If the fd is a listen socket,
2088 // then the "callback" parameter is NULL. If it is an actual read/write socket, then the "callback"
2089 // parameter is not null. This is important because we use waitable events for the listen socket
2090 // and alertable I/O for the read/write sockets.
2096 sock
= malloc( sizeof( TCPSocket
) );
2097 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
2098 mDNSPlatformMemZero( sock
, sizeof( TCPSocket
) );
2100 sock
->fd
= (SOCKET
) fd
;
2101 sock
->readEventHandler
= UDSCanRead
;
2102 sock
->userCallback
= callback
;
2103 sock
->userContext
= context
;
2104 sock
->m
= &gMDNSRecord
;
2106 err
= TCPAddSocket( sock
->m
, sock
);
2107 require_noerr( err
, exit
);
2109 *platform_data
= sock
;
2114 gUDSCallback
= callback
;
2115 gUDSEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2116 err
= translate_errno( gUDSEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2117 require_noerr( err
, exit
);
2118 err
= WSAEventSelect( fd
, gUDSEvent
, FD_ACCEPT
| FD_CLOSE
);
2119 err
= translate_errno( err
== 0, WSAGetLastError(), kNoResourcesErr
);
2120 require_noerr( err
, exit
);
2121 err
= RegisterWaitableEvent( &gMDNSRecord
, gUDSEvent
, context
, UDSCanAccept
);
2122 require_noerr( err
, exit
);
2132 udsSupportReadFD( SocketRef fd
, char *buf
, int len
, int flags
, void *platform_data
)
2140 sock
= ( TCPSocket
* ) platform_data
;
2141 require_action( sock
, exit
, ret
= -1 );
2142 require_action( sock
->fd
== fd
, exit
, ret
= -1 );
2144 ret
= mDNSPlatformReadTCP( sock
, buf
, len
, &closed
);
2158 udsSupportRemoveFDFromEventLoop( SocketRef fd
, void *platform_data
) // Note: This also CLOSES the socket
2160 mStatus err
= kNoErr
;
2162 if ( platform_data
!= NULL
)
2166 dlog( kDebugLevelInfo
, DEBUG_NAME
"session closed\n" );
2167 sock
= ( TCPSocket
* ) platform_data
;
2168 check( sock
->fd
== fd
);
2169 mDNSPlatformTCPCloseConnection( sock
);
2171 else if ( gUDSEvent
!= NULL
)
2173 UnregisterWaitableEvent( &gMDNSRecord
, gUDSEvent
);
2174 WSAEventSelect( fd
, gUDSEvent
, 0 );
2175 CloseHandle( gUDSEvent
);
2183 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
2191 //===========================================================================================================================
2192 // SystemWakeForNetworkAccess
2193 //===========================================================================================================================
2196 SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
)
2202 SYSTEM_POWER_STATUS powerStatus
;
2204 time_t nextWakeupTime
;
2208 dlog( kDebugLevelInfo
, DEBUG_NAME
"SystemWakeForNetworkAccess\n" );
2210 // Make sure we have a timer
2212 require_action( gSPSWakeupEvent
!= NULL
, exit
, ok
= FALSE
);
2213 require_action( gSPSSleepEvent
!= NULL
, exit
, ok
= FALSE
);
2215 // Make sure the user enabled bonjour sleep proxy client
2217 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\Power Management", &key
);
2218 require_action( !err
, exit
, ok
= FALSE
);
2219 dwSize
= sizeof( DWORD
);
2220 err
= RegQueryValueEx( key
, L
"Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
2221 require_action( !err
, exit
, ok
= FALSE
);
2222 require_action( enabled
, exit
, ok
= FALSE
);
2224 // Make sure machine is on AC power
2226 ok
= ( mDNSu8
) GetSystemPowerStatus( &powerStatus
);
2227 require_action( ok
, exit
, ok
= FALSE
);
2228 require_action( powerStatus
.ACLineStatus
== AC_LINE_ONLINE
, exit
, ok
= FALSE
);
2230 // Now make sure we have a network interface that does wake-on-lan
2232 ok
= ( mDNSu8
) IsWOMPEnabled( &gMDNSRecord
);
2233 require_action( ok
, exit
, ok
= FALSE
);
2235 // Now make sure we have advertised services. Doesn't make sense to
2236 // enable sleep proxy if we have no multicast services that could
2237 // potentially wake us up.
2239 ok
= ( mDNSu8
) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord
);
2240 require_action( ok
, exit
, ok
= FALSE
);
2242 // Calculate next wake up time
2244 startTime
= time( NULL
); // Seconds since midnight January 1, 1970
2245 nextWakeupTime
= startTime
+ ( 120 * 60 ); // 2 hours later
2247 if ( gMDNSRecord
.p
->nextDHCPLeaseExpires
< nextWakeupTime
)
2249 nextWakeupTime
= gMDNSRecord
.p
->nextDHCPLeaseExpires
;
2252 // Finally calculate the next relative wakeup time
2254 delta
= ( int )( ( ( double )( nextWakeupTime
- startTime
) ) * 0.9 );
2255 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "enabling sleep proxy client with next maintenance wake in %d seconds", delta
);
2257 // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
2259 timeout
->QuadPart
= -delta
;
2260 timeout
->QuadPart
*= kSecondsTo100NSUnits
;
2275 //===========================================================================================================================
2277 //===========================================================================================================================
2280 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
)
2282 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
2284 BOOL bOrder
= FALSE
;
2287 unsigned long int i
;
2290 // Find out how big our buffer needs to be.
2292 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
2293 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
2296 // Allocate the memory for the table
2298 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
2299 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
2302 // Now get the table.
2304 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
2305 require_noerr( err
, exit
);
2308 // Search for the row in the table we want.
2310 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
2312 if ( ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
) && ( !metric
|| ( pIpForwardTable
->table
[i
].dwForwardMetric1
== metric
) ) )
2314 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
2322 if ( pIpForwardTable
!= NULL
)
2324 free(pIpForwardTable
);
2331 //===========================================================================================================================
2333 //===========================================================================================================================
2336 IsValidAddress( const char * addr
)
2338 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
2342 //===========================================================================================================================
2343 // GetAdditionalMetric
2344 //===========================================================================================================================
2347 GetAdditionalMetric( DWORD ifIndex
)
2351 if( !gIPHelperLibraryInstance
)
2353 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
2355 gGetIpInterfaceEntryFunctionPtr
=
2356 (GetIpInterfaceEntryFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetIpInterfaceEntry" );
2358 if( !gGetIpInterfaceEntryFunctionPtr
)
2362 ok
= FreeLibrary( gIPHelperLibraryInstance
);
2363 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
2364 gIPHelperLibraryInstance
= NULL
;
2368 if ( gGetIpInterfaceEntryFunctionPtr
)
2370 MIB_IPINTERFACE_ROW row
;
2373 ZeroMemory( &row
, sizeof( MIB_IPINTERFACE_ROW
) );
2374 row
.Family
= AF_INET
;
2375 row
.InterfaceIndex
= ifIndex
;
2376 err
= gGetIpInterfaceEntryFunctionPtr( &row
);
2377 require_noerr( err
, exit
);
2378 metric
= row
.Metric
+ 256;
2387 //===========================================================================================================================
2389 //===========================================================================================================================
2392 SetLLRoute( mDNS
* const inMDNS
)
2394 OSStatus err
= kNoErr
;
2396 DEBUG_UNUSED( inMDNS
);
2399 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2400 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2402 // Don't mess w/ the routing table on Vista and later OSes, as
2403 // they have a permanent route to link-local addresses. Otherwise,
2404 // set a route to link local addresses (169.254.0.0)
2406 if ( ( gOSMajorVersion
< 6 ) && gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
2409 MIB_IPFORWARDROW rowExtant
;
2411 MIB_IPFORWARDROW row
;
2413 ZeroMemory(&row
, sizeof(row
));
2415 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
2416 require_noerr( err
, exit
);
2417 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
2418 row
.dwForwardIfIndex
= ifIndex
;
2419 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
2420 row
.dwForwardType
= 3;
2421 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
2422 row
.dwForwardAge
= 0;
2423 row
.dwForwardPolicy
= 0;
2424 row
.dwForwardMetric1
= 20 + GetAdditionalMetric( ifIndex
);
2425 row
.dwForwardMetric2
= (DWORD
) - 1;
2426 row
.dwForwardMetric3
= (DWORD
) - 1;
2427 row
.dwForwardMetric4
= (DWORD
) - 1;
2428 row
.dwForwardMetric5
= (DWORD
) - 1;
2433 // check to make sure we don't already have a route
2435 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
), 0 ) )
2438 // set the age to 0 so that we can do a memcmp.
2440 rowExtant
.dwForwardAge
= 0;
2443 // check to see if this route is the same as our route
2445 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
2448 // if it isn't then delete this entry
2450 DeleteIpForwardEntry(&rowExtant
);
2455 // else it is, so we don't want to create another route
2461 if (addRoute
&& row
.dwForwardNextHop
)
2463 err
= CreateIpForwardEntry(&row
);
2474 //===========================================================================================================================
2475 // GetRouteDestination
2476 //===========================================================================================================================
2479 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
2482 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
2483 IP_ADAPTER_INFO
* pAdapter
= NULL
;
2485 mDNSBool done
= mDNSfalse
;
2489 // GetBestInterface will fail if there is no default gateway
2490 // configured. If that happens, we will just take the first
2491 // interface in the list. MSDN support says there is no surefire
2492 // way to manually determine what the best interface might
2493 // be for a particular network address.
2495 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
2496 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2504 // Make an initial call to GetAdaptersInfo to get
2505 // the necessary size into the bufLen variable
2507 err
= GetAdaptersInfo( NULL
, &bufLen
);
2508 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2510 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2511 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2513 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2514 require_noerr( err
, exit
);
2516 pAdapter
= pAdapterInfo
;
2519 // <rdar://problem/3718122>
2520 // <rdar://problem/5652098>
2522 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2524 // If these interfaces are active (i.e., has a non-zero IP Address),
2525 // then we want to disable routing table modifications.
2529 if ( ( IsNortelVPN( pAdapter
) || IsJuniperVPN( pAdapter
) || IsCiscoVPN( pAdapter
) ) &&
2530 ( inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0 ) )
2532 dlog( kDebugLevelTrace
, DEBUG_NAME
"disabling routing table management due to VPN incompatibility" );
2536 pAdapter
= pAdapter
->Next
;
2541 pAdapter
= pAdapterInfo
;
2546 // If we don't have an interface selected, choose the first one that is of type ethernet and
2547 // has a valid IP Address
2549 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2551 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2552 *ifIndex
= pAdapter
->Index
;
2557 pAdapter
= pAdapter
->Next
;
2560 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2562 if ( !err
|| !( *ifIndex
) )
2567 // Otherwise, try again by wildcarding the interface
2577 if ( pAdapterInfo
!= NULL
)
2579 free( pAdapterInfo
);
2587 IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
)
2589 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2590 (pAdapter
->AddressLength
== 6) &&
2591 (pAdapter
->Address
[0] == 0x44) &&
2592 (pAdapter
->Address
[1] == 0x45) &&
2593 (pAdapter
->Address
[2] == 0x53) &&
2594 (pAdapter
->Address
[3] == 0x54) &&
2595 (pAdapter
->Address
[4] == 0x42) &&
2596 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2601 IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
)
2603 return ( strnistr( pAdapter
->Description
, "Juniper", sizeof( pAdapter
->Description
) ) != NULL
) ? true : false;
2608 IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
)
2610 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2611 (pAdapter
->AddressLength
== 6) &&
2612 (pAdapter
->Address
[0] == 0x00) &&
2613 (pAdapter
->Address
[1] == 0x05) &&
2614 (pAdapter
->Address
[2] == 0x9a) &&
2615 (pAdapter
->Address
[3] == 0x3c) &&
2616 (pAdapter
->Address
[4] == 0x7a) &&
2617 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2622 strnistr( const char * string
, const char * subString
, size_t max
)
2624 size_t subStringLen
;
2630 if ( ( string
== NULL
) || ( subString
== NULL
) )
2635 stringLen
= ( max
> strlen( string
) ) ? strlen( string
) : max
;
2637 if ( stringLen
== 0 )
2642 subStringLen
= strlen( subString
);
2644 if ( subStringLen
== 0 )
2649 if ( subStringLen
> stringLen
)
2654 maxOffset
= stringLen
- subStringLen
;
2657 for ( offset
= 0; offset
<= maxOffset
; offset
++ )
2659 if ( _strnicmp( pPos
, subString
, subStringLen
) == 0 )