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"
39 #include "mDNSDebug.h"
43 #if( !TARGET_OS_WINDOWS_CE )
55 #ifndef HeapEnableTerminationOnCorruption
56 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
60 #pragma mark == Constants ==
63 //===========================================================================================================================
65 //===========================================================================================================================
67 #define DEBUG_NAME "[mDNSWin32] "
68 #define kServiceFirewallName L"Bonjour"
69 #define kServiceDependencies TEXT("Tcpip\0\0")
70 #define kDNSServiceCacheEntryCountDefault 512
71 #define kRetryFirewallPeriod 30 * 1000
72 #define kDefValueSize MAX_PATH + 1
74 #define kDefaultRouteMetric 399
75 #define kSecondsTo100NSUnits ( 10 * 1000 * 1000 )
76 #define kSPSMaintenanceWakePeriod -30
77 #define kWaitToRetry (60 * 5)
79 #define RR_CACHE_SIZE 500
80 static CacheEntity gRRCache
[RR_CACHE_SIZE
];
82 #pragma mark == Structures ==
86 #pragma mark == Prototypes ==
89 //===========================================================================================================================
91 //===========================================================================================================================
92 static void Usage( void );
93 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
94 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
);
95 static OSStatus
RemoveService( LPCTSTR inName
);
96 static OSStatus
SetServiceParameters();
97 static OSStatus
GetServiceParameters();
98 static OSStatus
CheckFirewall();
99 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
);
100 static void ReportStatus( int inType
, const char *inFormat
, ... );
102 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] );
103 static OSStatus
ServiceSetupEventLogging( void );
104 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
);
106 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] );
107 static void ServiceStop( void );
109 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] );
110 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] );
111 static OSStatus
ServiceSpecificStop( void );
112 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] );
113 static mStatus
SetupServiceEvents();
114 static mStatus
TearDownServiceEvents();
115 static mStatus
SetupNotifications();
116 static mStatus
TearDownNotifications();
117 static void CALLBACK
StopNotification( HANDLE event
, void * context
);
118 static void CALLBACK
PowerSuspendNotification( HANDLE event
, void * context
);
119 static void CALLBACK
PowerResumeNotification( HANDLE event
, void * context
);
120 static void CALLBACK
InterfaceListNotification( SOCKET socket
, LPWSANETWORKEVENTS event
, void *context
);
121 static void CALLBACK
ComputerDescriptionNotification( HANDLE event
, void *context
);
122 static void CALLBACK
TCPChangedNotification( HANDLE event
, void *context
);
123 static void CALLBACK
DDNSChangedNotification( HANDLE event
, void *context
);
124 static void CALLBACK
FileSharingChangedNotification( HANDLE event
, void *context
);
125 static void CALLBACK
FirewallChangedNotification( HANDLE event
, void *context
);
126 static void CALLBACK
AdvertisedServicesChangedNotification( HANDLE event
, void *context
);
127 static void CALLBACK
SPSWakeupNotification( HANDLE event
, void *context
);
128 static void CALLBACK
SPSSleepNotification( HANDLE event
, void *context
);
129 static void CALLBACK
UDSAcceptNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
);
130 static void CALLBACK
UDSReadNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
);
131 static void CoreCallback(mDNS
* const inMDNS
, mStatus result
);
132 static mDNSu8
SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
);
133 static OSStatus
GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
);
134 static OSStatus
SetLLRoute( mDNS
* const inMDNS
);
135 static bool HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
);
136 static bool IsValidAddress( const char * addr
);
137 static bool IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
);
138 static bool IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
);
139 static bool IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
);
140 static const char * strnistr( const char * string
, const char * subString
, size_t max
);
143 # define StrLen(X) wcslen(X)
144 # define StrCmp(X,Y) wcscmp(X,Y)
146 # define StrLen(X) strlen(X)
147 # define StrCmp(X,Y) strcmp(X,Y)
151 #define kLLNetworkAddr "169.254.0.0"
152 #define kLLNetworkAddrMask "255.255.0.0"
155 #include "mDNSEmbeddedAPI.h"
158 #pragma mark == Globals ==
161 //===========================================================================================================================
163 //===========================================================================================================================
164 #define gMDNSRecord mDNSStorage
165 DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage
;
166 DEBUG_LOCAL BOOL gServiceQuietMode
= FALSE
;
167 DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable
[] =
169 { kServiceName
, ServiceMain
},
172 DEBUG_LOCAL HANDLE gStopEvent
= NULL
;
173 DEBUG_LOCAL HANDLE gPowerSuspendEvent
= NULL
;
174 DEBUG_LOCAL HANDLE gPowerSuspendAckEvent
= NULL
;
175 DEBUG_LOCAL HANDLE gPowerResumeEvent
= NULL
;
176 DEBUG_LOCAL SOCKET gInterfaceListChangedSocket
= INVALID_SOCKET
;
177 DEBUG_LOCAL HKEY gDescKey
= NULL
;
178 DEBUG_LOCAL HANDLE gDescChangedEvent
= NULL
; // Computer description changed event
179 DEBUG_LOCAL HKEY gTcpipKey
= NULL
;
180 DEBUG_LOCAL HANDLE gTcpipChangedEvent
= NULL
; // TCP/IP config changed
181 DEBUG_LOCAL HKEY gDdnsKey
= NULL
;
182 DEBUG_LOCAL HANDLE gDdnsChangedEvent
= NULL
; // DynDNS config changed
183 DEBUG_LOCAL HKEY gFileSharingKey
= NULL
;
184 DEBUG_LOCAL HANDLE gFileSharingChangedEvent
= NULL
; // File Sharing changed
185 DEBUG_LOCAL HKEY gFirewallKey
= NULL
;
186 DEBUG_LOCAL HANDLE gFirewallChangedEvent
= NULL
; // Firewall changed
187 DEBUG_LOCAL HKEY gAdvertisedServicesKey
= NULL
;
188 DEBUG_LOCAL HANDLE gAdvertisedServicesChangedEvent
= NULL
; // Advertised services changed
189 DEBUG_LOCAL SERVICE_STATUS gServiceStatus
;
190 DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle
= NULL
;
191 DEBUG_LOCAL HANDLE gServiceEventSource
= NULL
;
192 DEBUG_LOCAL
bool gServiceAllowRemote
= false;
193 DEBUG_LOCAL
int gServiceCacheEntryCount
= 0; // 0 means to use the DNS-SD default.
194 DEBUG_LOCAL
bool gServiceManageLLRouting
= true;
195 DEBUG_LOCAL HANDLE gSPSWakeupEvent
= NULL
;
196 DEBUG_LOCAL HANDLE gSPSSleepEvent
= NULL
;
197 DEBUG_LOCAL SocketRef gUDSSocket
= 0;
198 DEBUG_LOCAL udsEventCallback gUDSCallback
= NULL
;
199 DEBUG_LOCAL BOOL gRetryFirewall
= FALSE
;
201 typedef DWORD ( WINAPI
* GetIpInterfaceEntryFunctionPtr
)( PMIB_IPINTERFACE_ROW
);
202 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
203 mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr
= NULL
;
210 //===========================================================================================================================
212 //===========================================================================================================================
213 int Main( int argc
, LPTSTR argv
[] )
220 HeapSetInformation( NULL
, HeapEnableTerminationOnCorruption
, NULL
, 0 );
222 debug_initialize( kDebugOutputTypeMetaConsole
);
223 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelVerbose
);
225 // Default to automatically starting the service dispatcher if no extra arguments are specified.
227 start
= ( argc
<= 1 );
231 for( i
= 1; i
< argc
; ++i
)
233 if( StrCmp( argv
[ i
], TEXT("-install") ) == 0 ) // Install
238 LoadString( GetModuleHandle( NULL
), IDS_SERVICE_DESCRIPTION
, desc
, sizeof( desc
) );
239 err
= InstallService( kServiceName
, kServiceName
, desc
, argv
[0] );
242 ReportStatus( EVENTLOG_ERROR_TYPE
, "install service failed (%d)\n", err
);
246 else if( StrCmp( argv
[ i
], TEXT("-remove") ) == 0 ) // Remove
248 err
= RemoveService( kServiceName
);
251 ReportStatus( EVENTLOG_ERROR_TYPE
, "remove service failed (%d)\n", err
);
255 else if( StrCmp( argv
[ i
], TEXT("-start") ) == 0 ) // Start
259 else if( StrCmp( argv
[ i
], TEXT("-server") ) == 0 ) // Server
261 err
= RunDirect( argc
, argv
);
264 ReportStatus( EVENTLOG_ERROR_TYPE
, "run service directly failed (%d)\n", err
);
268 else if( StrCmp( argv
[ i
], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
270 gServiceQuietMode
= !gServiceQuietMode
;
272 else if( ( StrCmp( argv
[ i
], TEXT("-help") ) == 0 ) || // Help
273 ( StrCmp( argv
[ i
], TEXT("-h") ) == 0 ) )
287 // Start the service dispatcher if requested. This does not return until all services have terminated. If any
288 // global initialization is needed, it should be done before starting the service dispatcher, but only if it
289 // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
293 ok
= StartServiceCtrlDispatcher( gServiceDispatchTable
);
294 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
297 ReportStatus( EVENTLOG_ERROR_TYPE
, "start service dispatcher failed (%d)\n", err
);
304 dlog( kDebugLevelTrace
, DEBUG_NAME
"exited (%d %m)\n", err
, err
);
305 _CrtDumpMemoryLeaks();
309 //===========================================================================================================================
311 //===========================================================================================================================
313 static void Usage( void )
315 fprintf( stderr
, "\n" );
316 fprintf( stderr
, "mDNSResponder 1.0d1\n" );
317 fprintf( stderr
, "\n" );
318 fprintf( stderr
, " <no args> Runs the service normally\n" );
319 fprintf( stderr
, " -install Creates the service and starts it\n" );
320 fprintf( stderr
, " -remove Stops the service and deletes it\n" );
321 fprintf( stderr
, " -start Starts the service dispatcher after processing all other arguments\n" );
322 fprintf( stderr
, " -server Runs the service directly as a server (for debugging)\n" );
323 fprintf( stderr
, " -q Toggles Quiet Mode (no events or output)\n" );
324 fprintf( stderr
, " -remote Allow remote connections\n" );
325 fprintf( stderr
, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault
);
326 fprintf( stderr
, " -h[elp] Display Help/Usage\n" );
327 fprintf( stderr
, "\n" );
330 //===========================================================================================================================
331 // ConsoleControlHandler
332 //===========================================================================================================================
334 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
340 switch( inControlEvent
)
343 case CTRL_BREAK_EVENT
:
344 case CTRL_CLOSE_EVENT
:
345 case CTRL_LOGOFF_EVENT
:
346 case CTRL_SHUTDOWN_EVENT
:
347 err
= ServiceSpecificStop();
348 require_noerr( err
, exit
);
361 //===========================================================================================================================
363 //===========================================================================================================================
365 static OSStatus
InstallService( LPCTSTR inName
, LPCTSTR inDisplayName
, LPCTSTR inDescription
, LPCTSTR inPath
)
371 TCHAR fullPath
[ MAX_PATH
];
378 // Get a full path to the executable since a relative path may have been specified.
380 size
= GetFullPathName( inPath
, MAX_PATH
, fullPath
, &namePtr
);
381 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
382 require_noerr( err
, exit
);
384 // Create the service and start it.
386 scm
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
387 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
388 require_noerr( err
, exit
);
390 service
= CreateService( scm
, inName
, inDisplayName
, SERVICE_ALL_ACCESS
, SERVICE_WIN32_SHARE_PROCESS
,
391 SERVICE_AUTO_START
, SERVICE_ERROR_NORMAL
, fullPath
, NULL
, NULL
, kServiceDependencies
,
393 err
= translate_errno( service
, (OSStatus
) GetLastError(), kDuplicateErr
);
394 require_noerr( err
, exit
);
396 err
= SetServiceParameters();
401 err
= SetServiceInfo( scm
, inName
, inDescription
);
405 ok
= StartService( service
, 0, NULL
);
406 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kInUseErr
);
407 require_noerr( err
, exit
);
409 ReportStatus( EVENTLOG_SUCCESS
, "installed service\n" );
415 CloseServiceHandle( service
);
419 CloseServiceHandle( scm
);
424 //===========================================================================================================================
426 //===========================================================================================================================
428 static OSStatus
RemoveService( LPCTSTR inName
)
434 SERVICE_STATUS status
;
439 // Open a connection to the service.
441 scm
= OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS
);
442 err
= translate_errno( scm
, (OSStatus
) GetLastError(), kOpenErr
);
443 require_noerr( err
, exit
);
445 service
= OpenService( scm
, inName
, SERVICE_STOP
| SERVICE_QUERY_STATUS
| DELETE
);
446 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
447 require_noerr( err
, exit
);
449 // Stop the service, if it is not already stopped, then delete it.
451 ok
= QueryServiceStatus( service
, &status
);
452 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
453 require_noerr( err
, exit
);
455 if( status
.dwCurrentState
!= SERVICE_STOPPED
)
457 ok
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
458 check_translated_errno( ok
, (OSStatus
) GetLastError(), kAuthenticationErr
);
461 ok
= DeleteService( service
);
462 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kDeletedErr
);
463 require_noerr( err
, exit
);
465 ReportStatus( EVENTLOG_SUCCESS
, "Removed service\n" );
471 CloseServiceHandle( service
);
475 CloseServiceHandle( scm
);
482 //===========================================================================================================================
483 // SetServiceParameters
484 //===========================================================================================================================
486 static OSStatus
SetServiceParameters()
489 DWORD valueLen
= sizeof(DWORD
);
497 // Add/Open Parameters section under service entry in registry
499 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
500 require_noerr( err
, exit
);
503 // If the value isn't already there, then we create it
505 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
507 if (err
!= ERROR_SUCCESS
)
511 err
= RegSetValueEx( key
, kServiceManageLLRouting
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof(DWORD
) );
512 require_noerr( err
, exit
);
527 //===========================================================================================================================
528 // GetServiceParameters
529 //===========================================================================================================================
531 static OSStatus
GetServiceParameters()
542 // Add/Open Parameters section under service entry in registry
544 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
545 require_noerr( err
, exit
);
547 valueLen
= sizeof(DWORD
);
548 err
= RegQueryValueEx(key
, kServiceManageLLRouting
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
549 if (err
== ERROR_SUCCESS
)
551 gServiceManageLLRouting
= (value
) ? true : false;
554 valueLen
= sizeof(DWORD
);
555 err
= RegQueryValueEx(key
, kServiceCacheEntryCount
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
556 if (err
== ERROR_SUCCESS
)
558 gServiceCacheEntryCount
= value
;
572 //===========================================================================================================================
574 //===========================================================================================================================
576 static OSStatus
CheckFirewall()
581 ENUM_SERVICE_STATUS
* lpService
= NULL
;
585 DWORD bytesNeeded
= 0;
587 DWORD resumeHandle
= 0;
592 BOOL isRunning
= FALSE
;
593 OSStatus err
= kUnknownErr
;
595 // Check to see if the firewall service is running. If it isn't, then
596 // we want to return immediately
598 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
599 err
= translate_errno( sc
, GetLastError(), kUnknownErr
);
600 require_noerr( err
, exit
);
602 srvType
= SERVICE_WIN32
;
603 srvState
= SERVICE_STATE_ALL
;
607 // Call EnumServicesStatus using the handle returned by OpenSCManager
609 ok
= EnumServicesStatus ( sc
, srvType
, srvState
, lpService
, dwBytes
, &bytesNeeded
, &srvCount
, &resumeHandle
);
611 if ( ok
|| ( GetLastError() != ERROR_MORE_DATA
) )
621 dwBytes
= bytesNeeded
;
623 lpService
= ( ENUM_SERVICE_STATUS
* ) malloc( dwBytes
);
624 require_action( lpService
, exit
, err
= mStatus_NoMemoryErr
);
627 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
628 require_noerr( err
, exit
);
630 for ( i
= 0; i
< srvCount
; i
++ )
632 if ( wcscmp( lpService
[i
].lpServiceName
, L
"SharedAccess" ) == 0 )
634 if ( lpService
[i
].ServiceStatus
.dwCurrentState
== SERVICE_RUNNING
)
643 require_action( isRunning
, exit
, err
= kUnknownErr
);
645 // Check to see if we've managed the firewall.
646 // This package might have been installed, then
647 // the OS was upgraded to SP2 or above. If that's
648 // the case, then we need to manipulate the firewall
649 // so networking works correctly.
651 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
, &key
);
652 require_noerr( err
, exit
);
654 valueLen
= sizeof(DWORD
);
655 err
= RegQueryValueEx(key
, kServiceManageFirewall
, 0, &type
, (LPBYTE
) &value
, &valueLen
);
657 if ((err
!= ERROR_SUCCESS
) || (value
== 0))
659 wchar_t fullPath
[ MAX_PATH
];
662 // Get a full path to the executable
664 size
= GetModuleFileNameW( NULL
, fullPath
, MAX_PATH
);
665 err
= translate_errno( size
> 0, (OSStatus
) GetLastError(), kPathErr
);
666 require_noerr( err
, exit
);
668 err
= mDNSAddToFirewall(fullPath
, kServiceFirewallName
);
669 require_noerr( err
, exit
);
672 err
= RegSetValueEx( key
, kServiceManageFirewall
, 0, REG_DWORD
, (const LPBYTE
) &value
, sizeof( DWORD
) );
673 require_noerr( err
, exit
);
690 CloseServiceHandle ( sc
);
698 //===========================================================================================================================
700 //===========================================================================================================================
702 static OSStatus
SetServiceInfo( SC_HANDLE inSCM
, LPCTSTR inServiceName
, LPCTSTR inDescription
)
707 SERVICE_DESCRIPTION description
;
708 SERVICE_FAILURE_ACTIONS actions
;
712 check( inServiceName
);
713 check( inDescription
);
718 // Open the database (if not provided) and lock it to prevent other access while re-configuring.
722 inSCM
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
723 err
= translate_errno( inSCM
, (OSStatus
) GetLastError(), kOpenErr
);
724 require_noerr( err
, exit
);
727 lock
= LockServiceDatabase( inSCM
);
728 err
= translate_errno( lock
, (OSStatus
) GetLastError(), kInUseErr
);
729 require_noerr( err
, exit
);
731 // Open a handle to the service.
733 service
= OpenService( inSCM
, inServiceName
, SERVICE_CHANGE_CONFIG
|SERVICE_START
);
734 err
= translate_errno( service
, (OSStatus
) GetLastError(), kNotFoundErr
);
735 require_noerr( err
, exit
);
737 // Change the description.
739 description
.lpDescription
= (LPTSTR
) inDescription
;
740 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_DESCRIPTION
, &description
);
741 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
742 require_noerr( err
, exit
);
744 actions
.dwResetPeriod
= INFINITE
;
745 actions
.lpRebootMsg
= NULL
;
746 actions
.lpCommand
= NULL
;
747 actions
.cActions
= 1;
748 actions
.lpsaActions
= &action
;
750 action
.Type
= SC_ACTION_RESTART
;
752 ok
= ChangeServiceConfig2( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &actions
);
753 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kParamErr
);
754 require_noerr( err
, exit
);
759 // Close the service and release the lock.
763 CloseServiceHandle( service
);
767 UnlockServiceDatabase( lock
);
772 //===========================================================================================================================
774 //===========================================================================================================================
776 static void ReportStatus( int inType
, const char *inFormat
, ... )
778 if( !gServiceQuietMode
)
782 va_start( args
, inFormat
);
783 if( gServiceEventSource
)
787 const char * array
[ 1 ];
789 vsnprintf( s
, sizeof( s
), inFormat
, args
);
791 ok
= ReportEventA( gServiceEventSource
, (WORD
) inType
, 0, MDNSRESPONDER_LOG
, NULL
, 1, 0, array
, NULL
);
792 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
798 n
= vfprintf( stderr
, inFormat
, args
);
805 //===========================================================================================================================
807 //===========================================================================================================================
809 int RunDirect( int argc
, LPTSTR argv
[] )
817 err
= SetupServiceEvents();
818 require_noerr( err
, exit
);
820 // Install a Console Control Handler to handle things like control-c signals.
822 ok
= SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
823 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
824 require_noerr( err
, exit
);
826 err
= ServiceSpecificInitialize( argc
, argv
);
827 require_noerr( err
, exit
);
830 // Run the service. This does not return until the service quits or is stopped.
832 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Running service directly\n" );
834 err
= ServiceSpecificRun( argc
, argv
);
835 require_noerr( err
, exit
);
842 ServiceSpecificFinalize( argc
, argv
);
845 TearDownServiceEvents();
854 //===========================================================================================================================
856 //===========================================================================================================================
858 static void WINAPI
ServiceMain( DWORD argc
, LPTSTR argv
[] )
863 err
= SetupServiceEvents();
864 require_noerr( err
, exit
);
866 err
= ServiceSetupEventLogging();
869 err
= GetServiceParameters();
872 // Initialize the service status and register the service control handler with the name of the service.
874 gServiceStatus
.dwServiceType
= SERVICE_WIN32_SHARE_PROCESS
;
875 gServiceStatus
.dwCurrentState
= 0;
876 gServiceStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_SHUTDOWN
|SERVICE_ACCEPT_POWEREVENT
;
877 gServiceStatus
.dwWin32ExitCode
= NO_ERROR
;
878 gServiceStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
879 gServiceStatus
.dwCheckPoint
= 0;
880 gServiceStatus
.dwWaitHint
= 0;
882 gServiceStatusHandle
= RegisterServiceCtrlHandlerEx( argv
[ 0 ], ServiceControlHandler
, NULL
);
883 err
= translate_errno( gServiceStatusHandle
, (OSStatus
) GetLastError(), kInUseErr
);
884 require_noerr( err
, exit
);
886 // Mark the service as starting.
888 gServiceStatus
.dwCurrentState
= SERVICE_START_PENDING
;
889 gServiceStatus
.dwCheckPoint
= 0;
890 gServiceStatus
.dwWaitHint
= 5000; // 5 seconds
891 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
892 check_translated_errno( ok
, GetLastError(), kParamErr
);
894 // Run the service. This does not return until the service quits or is stopped.
896 err
= ServiceRun( (int) argc
, argv
);
899 gServiceStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
900 gServiceStatus
.dwServiceSpecificExitCode
= (DWORD
) err
;
903 // Service-specific work is done so mark the service as stopped.
905 gServiceStatus
.dwCurrentState
= SERVICE_STOPPED
;
906 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
907 check_translated_errno( ok
, GetLastError(), kParamErr
);
909 // Note: The service status handle should not be closed according to Microsoft documentation.
913 if( gServiceEventSource
)
915 ok
= DeregisterEventSource( gServiceEventSource
);
916 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
917 gServiceEventSource
= NULL
;
920 TearDownServiceEvents();
923 //===========================================================================================================================
924 // ServiceSetupEventLogging
925 //===========================================================================================================================
927 static OSStatus
ServiceSetupEventLogging( void )
932 DWORD typesSupported
;
933 TCHAR path
[ MAX_PATH
];
938 // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
940 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName
;
941 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, s
, &key
);
942 require_noerr( err
, exit
);
944 // Add the name to the EventMessageFile subkey.
947 GetModuleFileName( NULL
, path
, MAX_PATH
);
948 n
= (DWORD
) ( ( StrLen( path
) + 1 ) * sizeof( TCHAR
) );
949 err
= RegSetValueEx( key
, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ
, (const LPBYTE
) path
, n
);
950 require_noerr( err
, exit
);
952 // Set the supported event types in the TypesSupported subkey.
956 | EVENTLOG_ERROR_TYPE
957 | EVENTLOG_WARNING_TYPE
958 | EVENTLOG_INFORMATION_TYPE
959 | EVENTLOG_AUDIT_SUCCESS
960 | EVENTLOG_AUDIT_FAILURE
;
961 err
= RegSetValueEx( key
, TEXT("TypesSupported"), 0, REG_DWORD
, (const LPBYTE
) &typesSupported
, sizeof( DWORD
) );
962 require_noerr( err
, exit
);
964 // Set up the event source.
966 gServiceEventSource
= RegisterEventSource( NULL
, kServiceName
);
967 err
= translate_errno( gServiceEventSource
, (OSStatus
) GetLastError(), kParamErr
);
968 require_noerr( err
, exit
);
979 //===========================================================================================================================
980 // ServiceControlHandler
981 //===========================================================================================================================
983 static DWORD WINAPI
ServiceControlHandler( DWORD inControl
, DWORD inEventType
, LPVOID inEventData
, LPVOID inContext
)
989 DEBUG_UNUSED( inEventData
);
990 DEBUG_UNUSED( inContext
);
995 case SERVICE_CONTROL_STOP
:
996 case SERVICE_CONTROL_SHUTDOWN
:
998 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
1004 case SERVICE_CONTROL_POWEREVENT
:
1006 if (inEventType
== PBT_APMSUSPEND
)
1008 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: PBT_APMSUSPEND\n" );
1010 if ( gPowerSuspendEvent
)
1012 ok
= SetEvent( gPowerSuspendEvent
);
1013 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1016 switch ( WaitForSingleObject( gPowerSuspendAckEvent
, 5 * 1000 ) )
1026 dlog( kDebugLevelError
, DEBUG_NAME
"Timed out waiting for acknowledgement of machine sleep\n" );
1027 ReportStatus( EVENTLOG_ERROR_TYPE
, "Timed out waiting for acknowledgement of machine sleep" );
1033 dlog( kDebugLevelError
, DEBUG_NAME
"Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
1034 ReportStatus( EVENTLOG_ERROR_TYPE
, "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
1040 else if (inEventType
== PBT_APMRESUMESUSPEND
)
1042 dlog( kDebugLevelInfo
, DEBUG_NAME
"ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
1044 if ( gPowerResumeEvent
)
1046 ok
= SetEvent( gPowerResumeEvent
);
1047 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1055 dlog( kDebugLevelNotice
, DEBUG_NAME
"ServiceControlHandler: event (0x%08X)\n", inControl
);
1059 if( setStatus
&& gServiceStatusHandle
)
1061 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1062 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
1068 //===========================================================================================================================
1070 //===========================================================================================================================
1072 static OSStatus
ServiceRun( int argc
, LPTSTR argv
[] )
1078 DEBUG_UNUSED( argc
);
1079 DEBUG_UNUSED( argv
);
1081 initialized
= FALSE
;
1083 // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
1084 // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
1085 // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
1086 // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
1087 // any installers that are waiting for our state to change.
1089 gServiceStatus
.dwCurrentState
= SERVICE_RUNNING
;
1090 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1091 check_translated_errno( ok
, GetLastError(), kParamErr
);
1093 // Initialize the service-specific stuff
1099 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service initializing" );
1101 err
= ServiceSpecificInitialize( argc
, argv
);
1105 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service initialized" );
1109 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service initialization failed with err %d. Waiting %d seconds to retry...", err
, kWaitToRetry
);
1111 ret
= WaitForSingleObject( gStopEvent
, 1000 * kWaitToRetry
);
1113 if ( ret
== WAIT_OBJECT_0
)
1115 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service received a stop event" );
1118 else if ( ret
== WAIT_OBJECT_0
+ 1 )
1120 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service received a power suspend event" );
1122 else if ( ret
== WAIT_OBJECT_0
+ 2 )
1124 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service received a power resume event" );
1126 else if ( ret
!= WAIT_TIMEOUT
)
1128 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service received an error in WaitForSingleObject() : %d, %d", ret
, GetLastError() );
1135 err
= CheckFirewall();
1140 gRetryFirewall
= TRUE
;
1143 // Run the service-specific stuff. This does not return until the service quits or is stopped.
1145 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service started\n" );
1147 err
= ServiceSpecificRun( argc
, argv
);
1148 require_noerr( err
, exit
);
1152 // Service stopped. Clean up and we're done.
1154 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Service stopped (%d)\n", err
);
1158 ServiceSpecificFinalize( argc
, argv
);
1164 //===========================================================================================================================
1166 //===========================================================================================================================
1168 static void ServiceStop( void )
1173 // Signal the event to cause the service to exit.
1175 if( gServiceStatusHandle
)
1177 gServiceStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
1178 ok
= SetServiceStatus( gServiceStatusHandle
, &gServiceStatus
);
1179 check_translated_errno( ok
, GetLastError(), kParamErr
);
1182 err
= ServiceSpecificStop();
1189 #pragma mark == Service Specific ==
1192 //===========================================================================================================================
1193 // ServiceSpecificInitialize
1194 //===========================================================================================================================
1196 static OSStatus
ServiceSpecificInitialize( int argc
, LPTSTR argv
[] )
1200 DEBUG_UNUSED( argc
);
1201 DEBUG_UNUSED( argv
);
1203 mDNSPlatformMemZero( &gMDNSRecord
, sizeof gMDNSRecord
);
1204 mDNSPlatformMemZero( &gPlatformStorage
, sizeof gPlatformStorage
);
1206 gPlatformStorage
.reportStatusFunc
= ReportStatus
;
1208 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1209 require_noerr( err
, exit
);
1211 err
= SetupNotifications();
1214 err
= udsserver_init(mDNSNULL
, 0);
1215 require_noerr( err
, exit
);
1217 SetLLRoute( &gMDNSRecord
);
1222 ServiceSpecificFinalize( argc
, argv
);
1227 //===========================================================================================================================
1228 // ServiceSpecificRun
1229 //===========================================================================================================================
1231 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1233 mDNSBool done
= mDNSfalse
;
1234 mStatus err
= mStatus_NoError
;
1236 DEBUG_UNUSED( argc
);
1237 DEBUG_UNUSED( argv
);
1239 err
= SetupInterfaceList( &gMDNSRecord
);
1242 err
= uDNS_SetupDNSConfig( &gMDNSRecord
);
1247 static mDNSs32 RepeatedBusy
= 0;
1248 mDNSs32 nextTimerEvent
;
1251 // Give the mDNS core a chance to do its work and determine next event time.
1253 nextTimerEvent
= udsserver_idle( mDNS_Execute( &gMDNSRecord
) - mDNS_TimeNow( &gMDNSRecord
) );
1255 if ( nextTimerEvent
< 0) nextTimerEvent
= 0;
1256 else if ( nextTimerEvent
> (0x7FFFFFFF / 1000)) nextTimerEvent
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
1257 else nextTimerEvent
= ( nextTimerEvent
* 1000) / mDNSPlatformOneSecond
;
1259 // Debugging sanity check, to guard against CPU spins
1261 if ( nextTimerEvent
> 0 )
1269 if ( ++RepeatedBusy
>= mDNSPlatformOneSecond
)
1271 ShowTaskSchedulingError( &gMDNSRecord
);
1276 if ( gMDNSRecord
.ShutdownTime
)
1278 mDNSs32 now
= mDNS_TimeNow( &gMDNSRecord
);
1280 if ( mDNS_ExitNow( &gMDNSRecord
, now
) )
1282 mDNS_FinalExit( &gMDNSRecord
);
1287 if ( nextTimerEvent
- gMDNSRecord
.ShutdownTime
>= 0 )
1289 nextTimerEvent
= gMDNSRecord
.ShutdownTime
;
1293 err
= mDNSPoll( nextTimerEvent
);
1299 err
= SetupInterfaceList( &gMDNSRecord
);
1302 err
= uDNS_SetupDNSConfig( &gMDNSRecord
);
1313 //===========================================================================================================================
1314 // ServiceSpecificStop
1315 //===========================================================================================================================
1317 static OSStatus
ServiceSpecificStop( void )
1322 ok
= SetEvent(gStopEvent
);
1323 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1324 require_noerr( err
, exit
);
1331 //===========================================================================================================================
1332 // ServiceSpecificFinalize
1333 //===========================================================================================================================
1335 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1337 DEBUG_UNUSED( argc
);
1338 DEBUG_UNUSED( argv
);
1341 // clean up the notifications
1343 TearDownNotifications();
1346 // clean up loaded library
1349 if( gIPHelperLibraryInstance
)
1351 gGetIpInterfaceEntryFunctionPtr
= NULL
;
1353 FreeLibrary( gIPHelperLibraryInstance
);
1354 gIPHelperLibraryInstance
= NULL
;
1359 //===========================================================================================================================
1360 // SetupServiceEvents
1361 //===========================================================================================================================
1363 mDNSlocal mStatus
SetupServiceEvents()
1369 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1370 err
= translate_errno( gStopEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1371 require_noerr( err
, exit
);
1377 TearDownServiceEvents();
1384 //===========================================================================================================================
1385 // TearDownServiceNotifications
1386 //===========================================================================================================================
1388 mDNSlocal mStatus
TearDownServiceEvents()
1392 CloseHandle( gStopEvent
);
1396 return mStatus_NoError
;
1400 //===========================================================================================================================
1401 // SetupNotifications
1402 //===========================================================================================================================
1404 mDNSlocal mStatus
SetupNotifications()
1408 unsigned long param
;
1413 require_action( gStopEvent
, exit
, err
= kUnknownErr
);
1414 err
= mDNSPollRegisterEvent( gStopEvent
, StopNotification
, NULL
);
1415 require_noerr( err
, exit
);
1419 gPowerSuspendEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1420 err
= translate_errno( gPowerSuspendEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1421 require_noerr( err
, exit
);
1422 err
= mDNSPollRegisterEvent( gPowerSuspendEvent
, PowerSuspendNotification
, NULL
);
1423 require_noerr( err
, exit
);
1425 // Power Suspend Ack
1427 gPowerSuspendAckEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1428 err
= translate_errno( gPowerSuspendAckEvent
, ( mStatus
) GetLastError(), kUnknownErr
);
1429 require_noerr( err
, exit
);
1433 gPowerResumeEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1434 err
= translate_errno( gPowerResumeEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1435 require_noerr( err
, exit
);
1436 err
= mDNSPollRegisterEvent( gPowerResumeEvent
, PowerResumeNotification
, NULL
);
1437 require_noerr( err
, exit
);
1439 // Register to listen for address list changes.
1441 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1442 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
1443 require_noerr( err
, exit
);
1444 gInterfaceListChangedSocket
= sock
;
1446 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1447 // when a change to the interface list is detected.
1450 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
1451 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
1452 require_noerr( err
, exit
);
1456 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1459 check( errno_compat() == WSAEWOULDBLOCK
);
1462 err
= mDNSPollRegisterSocket( sock
, FD_ADDRESS_LIST_CHANGE
, InterfaceListNotification
, NULL
);
1463 require_noerr( err
, exit
);
1465 gDescChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
1466 err
= translate_errno( gDescChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1467 require_noerr( err
, exit
);
1469 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ
, &gDescKey
);
1470 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
1472 if ( gDescKey
!= NULL
)
1474 err
= RegNotifyChangeKeyValue( gDescKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, gDescChangedEvent
, TRUE
);
1475 require_noerr( err
, exit
);
1478 err
= mDNSPollRegisterEvent( gDescChangedEvent
, ComputerDescriptionNotification
, NULL
);
1479 require_noerr( err
, exit
);
1481 // This will catch all changes to tcp/ip networking, including changes to the domain search list
1483 gTcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1484 err
= translate_errno( gTcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1485 require_noerr( err
, exit
);
1486 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey
);
1487 require_noerr( err
, exit
);
1488 err
= RegNotifyChangeKeyValue( gTcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gTcpipChangedEvent
, TRUE
);
1489 require_noerr( err
, exit
);
1490 err
= mDNSPollRegisterEvent( gTcpipChangedEvent
, TCPChangedNotification
, NULL
);
1491 require_noerr( err
, exit
);
1493 // This will catch all changes to ddns configuration
1495 gDdnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1496 err
= translate_errno( gDdnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1497 require_noerr( err
, exit
);
1498 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &gDdnsKey
);
1499 require_noerr( err
, exit
);
1500 err
= RegNotifyChangeKeyValue( gDdnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gDdnsChangedEvent
, TRUE
);
1501 require_noerr( err
, exit
);
1502 err
= mDNSPollRegisterEvent( gDdnsChangedEvent
, DDNSChangedNotification
, NULL
);
1503 require_noerr( err
, exit
);
1505 // This will catch all changes to file sharing
1507 gFileSharingChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1508 err
= translate_errno( gFileSharingChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1509 require_noerr( err
, exit
);
1511 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey
);
1513 // Just to make sure that initialization doesn't fail on some old OS
1514 // that doesn't have this key, we'll only add the notification if
1519 err
= RegNotifyChangeKeyValue( gFileSharingKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFileSharingChangedEvent
, TRUE
);
1520 require_noerr( err
, exit
);
1521 err
= mDNSPollRegisterEvent( gFileSharingChangedEvent
, FileSharingChangedNotification
, NULL
);
1522 require_noerr( err
, exit
);
1526 err
= mStatus_NoError
;
1529 // This will catch changes to the Windows firewall
1531 gFirewallChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1532 err
= translate_errno( gFirewallChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1533 require_noerr( err
, exit
);
1535 // Just to make sure that initialization doesn't fail on some old OS
1536 // that doesn't have this key, we'll only add the notification if
1539 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey
);
1543 err
= RegNotifyChangeKeyValue( gFirewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFirewallChangedEvent
, TRUE
);
1544 require_noerr( err
, exit
);
1545 err
= mDNSPollRegisterEvent( gFirewallChangedEvent
, FirewallChangedNotification
, NULL
);
1546 require_noerr( err
, exit
);
1550 err
= mStatus_NoError
;
1553 // This will catch all changes to advertised services configuration
1555 gAdvertisedServicesChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1556 err
= translate_errno( gAdvertisedServicesChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1557 require_noerr( err
, exit
);
1558 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\Services"), &gAdvertisedServicesKey
);
1559 require_noerr( err
, exit
);
1560 err
= RegNotifyChangeKeyValue( gAdvertisedServicesKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gAdvertisedServicesChangedEvent
, TRUE
);
1561 require_noerr( err
, exit
);
1562 err
= mDNSPollRegisterEvent( gAdvertisedServicesChangedEvent
, AdvertisedServicesChangedNotification
, NULL
);
1563 require_noerr( err
, exit
);
1567 gSPSWakeupEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1568 err
= translate_errno( gSPSWakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1569 require_noerr( err
, exit
);
1570 err
= mDNSPollRegisterEvent( gSPSWakeupEvent
, SPSWakeupNotification
, NULL
);
1571 require_noerr( err
, exit
);
1575 gSPSSleepEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1576 err
= translate_errno( gSPSSleepEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1577 require_noerr( err
, exit
);
1578 err
= mDNSPollRegisterEvent( gSPSSleepEvent
, SPSSleepNotification
, NULL
);
1579 require_noerr( err
, exit
);
1584 TearDownNotifications();
1589 //===========================================================================================================================
1590 // TearDownNotifications
1591 //===========================================================================================================================
1593 mDNSlocal mStatus
TearDownNotifications()
1595 if( IsValidSocket( gInterfaceListChangedSocket
) )
1597 mDNSPollUnregisterSocket( gInterfaceListChangedSocket
);
1599 close_compat( gInterfaceListChangedSocket
);
1600 gInterfaceListChangedSocket
= kInvalidSocketRef
;
1603 if ( gDescChangedEvent
!= NULL
)
1605 mDNSPollUnregisterEvent( gDescChangedEvent
);
1606 CloseHandle( gDescChangedEvent
);
1607 gDescChangedEvent
= NULL
;
1610 if ( gDescKey
!= NULL
)
1612 RegCloseKey( gDescKey
);
1616 if ( gTcpipChangedEvent
!= NULL
)
1618 mDNSPollUnregisterEvent( gTcpipChangedEvent
);
1619 CloseHandle( gTcpipChangedEvent
);
1620 gTcpipChangedEvent
= NULL
;
1623 if ( gDdnsChangedEvent
!= NULL
)
1625 mDNSPollUnregisterEvent( gDdnsChangedEvent
);
1626 CloseHandle( gDdnsChangedEvent
);
1627 gDdnsChangedEvent
= NULL
;
1630 if ( gDdnsKey
!= NULL
)
1632 RegCloseKey( gDdnsKey
);
1636 if ( gFileSharingChangedEvent
!= NULL
)
1638 mDNSPollUnregisterEvent( gFileSharingChangedEvent
);
1639 CloseHandle( gFileSharingChangedEvent
);
1640 gFileSharingChangedEvent
= NULL
;
1643 if ( gFileSharingKey
!= NULL
)
1645 RegCloseKey( gFileSharingKey
);
1646 gFileSharingKey
= NULL
;
1649 if ( gFirewallChangedEvent
!= NULL
)
1651 mDNSPollUnregisterEvent( gFirewallChangedEvent
);
1652 CloseHandle( gFirewallChangedEvent
);
1653 gFirewallChangedEvent
= NULL
;
1656 if ( gFirewallKey
!= NULL
)
1658 RegCloseKey( gFirewallKey
);
1659 gFirewallKey
= NULL
;
1662 if ( gAdvertisedServicesChangedEvent
!= NULL
)
1664 mDNSPollUnregisterEvent( gAdvertisedServicesChangedEvent
);
1665 CloseHandle( gAdvertisedServicesChangedEvent
);
1666 gAdvertisedServicesChangedEvent
= NULL
;
1669 if ( gAdvertisedServicesKey
!= NULL
)
1671 RegCloseKey( gAdvertisedServicesKey
);
1672 gAdvertisedServicesKey
= NULL
;
1675 if ( gSPSWakeupEvent
)
1677 mDNSPollUnregisterEvent( gSPSWakeupEvent
);
1678 CloseHandle( gSPSWakeupEvent
);
1679 gSPSWakeupEvent
= NULL
;
1682 if ( gSPSSleepEvent
)
1684 mDNSPollUnregisterEvent( gSPSSleepEvent
);
1685 CloseHandle( gSPSSleepEvent
);
1686 gSPSSleepEvent
= NULL
;
1689 if ( gPowerResumeEvent
)
1691 mDNSPollUnregisterEvent( gPowerResumeEvent
);
1692 CloseHandle( gPowerResumeEvent
);
1693 gPowerResumeEvent
= NULL
;
1696 if ( gPowerSuspendAckEvent
)
1698 CloseHandle( gPowerSuspendAckEvent
);
1699 gPowerSuspendAckEvent
= NULL
;
1702 if ( gPowerSuspendEvent
)
1704 mDNSPollUnregisterEvent( gPowerSuspendEvent
);
1705 CloseHandle( gPowerSuspendEvent
);
1706 gPowerSuspendEvent
= NULL
;
1711 mDNSPollUnregisterEvent( gStopEvent
);
1714 return( mStatus_NoError
);
1718 mDNSlocal
void CALLBACK
1719 StopNotification( HANDLE event
, void *context
)
1721 DEBUG_UNUSED( event
);
1722 DEBUG_UNUSED( context
);
1724 dlog( kDebugLevelVerbose
, DEBUG_NAME
"stopping...\n" );
1726 mDNS_StartExit( &gMDNSRecord
);
1730 mDNSlocal
void CALLBACK
1731 PowerSuspendNotification( HANDLE event
, void * context
)
1733 LARGE_INTEGER timeout
;
1736 DEBUG_UNUSED( event
);
1737 DEBUG_UNUSED( context
);
1739 dlog( kDebugLevelInfo
, DEBUG_NAME
"PowerSuspendNotification\n" );
1741 gMDNSRecord
.SystemWakeOnLANEnabled
= SystemWakeForNetworkAccess( &timeout
);
1743 if ( gMDNSRecord
.SystemWakeOnLANEnabled
)
1745 ok
= SetWaitableTimer( gSPSWakeupEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1749 mDNSCoreMachineSleep(&gMDNSRecord
, TRUE
);
1751 ok
= SetEvent( gPowerSuspendAckEvent
);
1755 dlog( kDebugLevelError
, DEBUG_NAME
"PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
1756 ReportStatus( EVENTLOG_ERROR_TYPE
, "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
1761 mDNSlocal
void CALLBACK
1762 PowerResumeNotification( HANDLE event
, void * context
)
1764 DEBUG_UNUSED( event
);
1765 DEBUG_UNUSED( context
);
1767 dlog( kDebugLevelInfo
, DEBUG_NAME
"PowerResumeNotification\n" );
1769 if ( gSPSWakeupEvent
)
1771 CancelWaitableTimer( gSPSWakeupEvent
);
1774 if ( gSPSSleepEvent
)
1776 CancelWaitableTimer( gSPSSleepEvent
);
1779 mDNSCoreMachineSleep(&gMDNSRecord
, FALSE
);
1784 mDNSlocal
void CALLBACK
1785 InterfaceListNotification( SOCKET socket
, LPWSANETWORKEVENTS event
, void *context
)
1792 DEBUG_UNUSED( socket
);
1793 DEBUG_UNUSED( event
);
1794 DEBUG_UNUSED( context
);
1796 // It would be nice to come up with a more elegant solution to this, but it seems that
1797 // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as
1798 // as a simple workaround, we'll pause for a couple of seconds before processing the change.
1800 // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1801 // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another
1802 // second on top of that to account for machine load or some other exigency.
1806 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1808 InterfaceListDidChange( &gMDNSRecord
);
1810 // reset the event handler
1813 err
= WSAIoctl( gInterfaceListChangedSocket
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1816 check( errno_compat() == WSAEWOULDBLOCK
);
1821 mDNSlocal
void CALLBACK
1822 ComputerDescriptionNotification( HANDLE event
, void *context
)
1824 // The computer description might have changed
1826 DEBUG_UNUSED( event
);
1827 DEBUG_UNUSED( context
);
1829 ComputerDescriptionDidChange( &gMDNSRecord
);
1830 udsserver_handle_configchange( &gMDNSRecord
);
1832 // and reset the event handler
1833 if ( ( gDescKey
!= NULL
) && ( gDescChangedEvent
!= NULL
) )
1835 int err
= RegNotifyChangeKeyValue( gDescKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, gDescChangedEvent
, TRUE
);
1841 mDNSlocal
void CALLBACK
1842 TCPChangedNotification( HANDLE event
, void *context
)
1844 // The TCP/IP might have changed
1846 DEBUG_UNUSED( event
);
1847 DEBUG_UNUSED( context
);
1849 TCPIPConfigDidChange( &gMDNSRecord
);
1850 udsserver_handle_configchange( &gMDNSRecord
);
1852 // and reset the event handler
1854 if ( ( gTcpipKey
!= NULL
) && ( gTcpipChangedEvent
) )
1856 int err
= RegNotifyChangeKeyValue( gTcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gTcpipChangedEvent
, TRUE
);
1862 mDNSlocal
void CALLBACK
1863 DDNSChangedNotification( HANDLE event
, void *context
)
1865 // The DynDNS config might have changed
1867 DEBUG_UNUSED( event
);
1868 DEBUG_UNUSED( context
);
1870 DynDNSConfigDidChange( &gMDNSRecord
);
1871 udsserver_handle_configchange( &gMDNSRecord
);
1873 // and reset the event handler
1875 if ((gDdnsKey
!= NULL
) && (gDdnsChangedEvent
))
1877 int err
= RegNotifyChangeKeyValue(gDdnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gDdnsChangedEvent
, TRUE
);
1883 mDNSlocal
void CALLBACK
1884 FileSharingChangedNotification( HANDLE event
, void *context
)
1886 // File sharing changed
1888 DEBUG_UNUSED( event
);
1889 DEBUG_UNUSED( context
);
1891 FileSharingDidChange( &gMDNSRecord
);
1893 // and reset the event handler
1895 if ((gFileSharingKey
!= NULL
) && (gFileSharingChangedEvent
))
1897 int err
= RegNotifyChangeKeyValue(gFileSharingKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFileSharingChangedEvent
, TRUE
);
1903 mDNSlocal
void CALLBACK
1904 FirewallChangedNotification( HANDLE event
, void *context
)
1906 // Firewall configuration changed
1908 DEBUG_UNUSED( event
);
1909 DEBUG_UNUSED( context
);
1911 FirewallDidChange( &gMDNSRecord
);
1913 // and reset the event handler
1915 if ((gFirewallKey
!= NULL
) && (gFirewallChangedEvent
))
1917 int err
= RegNotifyChangeKeyValue(gFirewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFirewallChangedEvent
, TRUE
);
1923 mDNSlocal
void CALLBACK
1924 AdvertisedServicesChangedNotification( HANDLE event
, void *context
)
1926 // Ultimately we'll want to manage multiple services, but right now the only service
1927 // we'll be managing is SMB.
1929 DEBUG_UNUSED( event
);
1930 DEBUG_UNUSED( context
);
1932 FileSharingDidChange( &gMDNSRecord
);
1934 // and reset the event handler
1936 if ( ( gAdvertisedServicesKey
!= NULL
) && ( gAdvertisedServicesChangedEvent
) )
1938 int err
= RegNotifyChangeKeyValue(gAdvertisedServicesKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gAdvertisedServicesChangedEvent
, TRUE
);
1944 mDNSlocal
void CALLBACK
1945 SPSWakeupNotification( HANDLE event
, void *context
)
1947 LARGE_INTEGER timeout
;
1949 DEBUG_UNUSED( event
);
1950 DEBUG_UNUSED( context
);
1952 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Maintenance wake" );
1954 timeout
.QuadPart
= kSPSMaintenanceWakePeriod
;
1955 timeout
.QuadPart
*= kSecondsTo100NSUnits
;
1957 SetWaitableTimer( gSPSSleepEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1961 mDNSlocal
void CALLBACK
1962 SPSSleepNotification( HANDLE event
, void *context
)
1964 DEBUG_UNUSED( event
);
1965 DEBUG_UNUSED( context
);
1967 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Returning to sleep after maintenance wake" );
1969 // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
1970 // call HandlePowerSuspend() explicity. This will reset the
1971 // maintenance wake timers.
1973 PowerSuspendNotification( gPowerSuspendEvent
, NULL
);
1974 SetSuspendState( FALSE
, FALSE
, FALSE
);
1978 //===========================================================================================================================
1980 //===========================================================================================================================
1983 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
1985 if (status
== mStatus_ConfigChanged
)
1987 SetLLRoute( inMDNS
);
1992 //===========================================================================================================================
1993 // UDSAcceptNotification
1994 //===========================================================================================================================
1996 mDNSlocal
void CALLBACK
1997 UDSAcceptNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
)
2005 gUDSCallback( ( int ) gUDSSocket
, 0, context
);
2010 //===========================================================================================================================
2011 // UDSReadNotification
2012 //===========================================================================================================================
2014 mDNSlocal
void CALLBACK
2015 UDSReadNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
)
2017 TCPSocket
*tcpSock
= ( TCPSocket
* ) context
;
2024 tcpSock
->userCallback( ( int ) tcpSock
->fd
, 0, tcpSock
->userContext
);
2029 //===========================================================================================================================
2030 // udsSupportAddFDToEventLoop
2031 //===========================================================================================================================
2034 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
, void **platform_data
)
2036 mStatus err
= mStatus_NoError
;
2038 // We are using some knowledge of what is being passed to us here. If the fd is a listen socket,
2039 // then the "context" parameter is NULL. If it is an actual read/write socket, then the "context"
2040 // parameter is not null.
2046 sock
= malloc( sizeof( TCPSocket
) );
2047 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
2048 mDNSPlatformMemZero( sock
, sizeof( TCPSocket
) );
2050 sock
->fd
= (SOCKET
) fd
;
2051 sock
->userCallback
= callback
;
2052 sock
->userContext
= context
;
2053 sock
->m
= &gMDNSRecord
;
2055 *platform_data
= sock
;
2057 err
= mDNSPollRegisterSocket( sock
->fd
, FD_READ
| FD_CLOSE
, UDSReadNotification
, sock
);
2058 require_noerr( err
, exit
);
2063 gUDSCallback
= callback
;
2065 err
= mDNSPollRegisterSocket( gUDSSocket
, FD_ACCEPT
| FD_CLOSE
, UDSAcceptNotification
, NULL
);
2066 require_noerr( err
, exit
);
2076 udsSupportReadFD( SocketRef fd
, char *buf
, int len
, int flags
, void *platform_data
)
2084 sock
= ( TCPSocket
* ) platform_data
;
2085 require_action( sock
, exit
, ret
= -1 );
2086 require_action( sock
->fd
== fd
, exit
, ret
= -1 );
2088 ret
= mDNSPlatformReadTCP( sock
, buf
, len
, &closed
);
2094 else if ( !ret
&& ( WSAGetLastError() == WSAEWOULDBLOCK
) )
2096 // mDNSPlatformReadTCP will return 0 if it gets WSAEWOULDBLOCK, but
2097 // that caller of this routine interprets that as close connection.
2098 // We'll fix that by returning -1 in that case.
2110 udsSupportRemoveFDFromEventLoop( SocketRef fd
, void *platform_data
) // Note: This also CLOSES the socket
2112 mStatus err
= kNoErr
;
2114 mDNSPollUnregisterSocket( fd
);
2116 if ( platform_data
!= NULL
)
2120 dlog( kDebugLevelInfo
, DEBUG_NAME
"session closed\n" );
2121 sock
= ( TCPSocket
* ) platform_data
;
2122 check( sock
->fd
== fd
);
2123 mDNSPlatformTCPCloseConnection( sock
);
2130 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
2138 //===========================================================================================================================
2139 // SystemWakeForNetworkAccess
2140 //===========================================================================================================================
2143 SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
)
2149 SYSTEM_POWER_STATUS powerStatus
;
2151 time_t nextWakeupTime
;
2155 dlog( kDebugLevelInfo
, DEBUG_NAME
"SystemWakeForNetworkAccess\n" );
2157 // Make sure we have a timer
2159 require_action( gSPSWakeupEvent
!= NULL
, exit
, ok
= FALSE
);
2160 require_action( gSPSSleepEvent
!= NULL
, exit
, ok
= FALSE
);
2162 // Make sure the user enabled bonjour sleep proxy client
2164 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\Power Management", &key
);
2165 require_action( !err
, exit
, ok
= FALSE
);
2166 dwSize
= sizeof( DWORD
);
2167 err
= RegQueryValueEx( key
, L
"Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
2168 require_action( !err
, exit
, ok
= FALSE
);
2169 require_action( enabled
, exit
, ok
= FALSE
);
2171 // Make sure machine is on AC power
2173 ok
= ( mDNSu8
) GetSystemPowerStatus( &powerStatus
);
2174 require_action( ok
, exit
, ok
= FALSE
);
2175 require_action( powerStatus
.ACLineStatus
== AC_LINE_ONLINE
, exit
, ok
= FALSE
);
2177 // Now make sure we have a network interface that does wake-on-lan
2179 ok
= ( mDNSu8
) IsWOMPEnabled( &gMDNSRecord
);
2180 require_action( ok
, exit
, ok
= FALSE
);
2182 // Now make sure we have advertised services. Doesn't make sense to
2183 // enable sleep proxy if we have no multicast services that could
2184 // potentially wake us up.
2186 ok
= ( mDNSu8
) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord
);
2187 require_action( ok
, exit
, ok
= FALSE
);
2189 // Calculate next wake up time
2191 startTime
= time( NULL
); // Seconds since midnight January 1, 1970
2192 nextWakeupTime
= startTime
+ ( 120 * 60 ); // 2 hours later
2194 if ( gMDNSRecord
.p
->nextDHCPLeaseExpires
< nextWakeupTime
)
2196 nextWakeupTime
= gMDNSRecord
.p
->nextDHCPLeaseExpires
;
2199 // Finally calculate the next relative wakeup time
2201 delta
= ( int )( ( ( double )( nextWakeupTime
- startTime
) ) * 0.9 );
2202 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "enabling sleep proxy client with next maintenance wake in %d seconds", delta
);
2204 // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
2206 timeout
->QuadPart
= -delta
;
2207 timeout
->QuadPart
*= kSecondsTo100NSUnits
;
2222 //===========================================================================================================================
2224 //===========================================================================================================================
2227 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
)
2229 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
2231 BOOL bOrder
= FALSE
;
2234 unsigned long int i
;
2237 // Find out how big our buffer needs to be.
2239 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
2240 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
2243 // Allocate the memory for the table
2245 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
2246 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
2249 // Now get the table.
2251 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
2252 require_noerr( err
, exit
);
2255 // Search for the row in the table we want.
2257 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
2259 if ( ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
) && ( !metric
|| ( pIpForwardTable
->table
[i
].dwForwardMetric1
== metric
) ) )
2261 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
2269 if ( pIpForwardTable
!= NULL
)
2271 free(pIpForwardTable
);
2278 //===========================================================================================================================
2280 //===========================================================================================================================
2283 IsValidAddress( const char * addr
)
2285 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
2289 //===========================================================================================================================
2290 // GetAdditionalMetric
2291 //===========================================================================================================================
2294 GetAdditionalMetric( DWORD ifIndex
)
2298 if( !gIPHelperLibraryInstance
)
2300 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
2302 gGetIpInterfaceEntryFunctionPtr
=
2303 (GetIpInterfaceEntryFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetIpInterfaceEntry" );
2305 if( !gGetIpInterfaceEntryFunctionPtr
)
2309 ok
= FreeLibrary( gIPHelperLibraryInstance
);
2310 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
2311 gIPHelperLibraryInstance
= NULL
;
2315 if ( gGetIpInterfaceEntryFunctionPtr
)
2317 MIB_IPINTERFACE_ROW row
;
2320 ZeroMemory( &row
, sizeof( MIB_IPINTERFACE_ROW
) );
2321 row
.Family
= AF_INET
;
2322 row
.InterfaceIndex
= ifIndex
;
2323 err
= gGetIpInterfaceEntryFunctionPtr( &row
);
2324 require_noerr( err
, exit
);
2325 metric
= row
.Metric
+ 256;
2334 //===========================================================================================================================
2336 //===========================================================================================================================
2339 SetLLRoute( mDNS
* const inMDNS
)
2341 OSStatus err
= kNoErr
;
2343 DEBUG_UNUSED( inMDNS
);
2346 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2347 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2349 // Don't mess w/ the routing table on Vista and later OSes, as
2350 // they have a permanent route to link-local addresses. Otherwise,
2351 // set a route to link local addresses (169.254.0.0)
2353 if ( ( inMDNS
->p
->osMajorVersion
< 6 ) && gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
2356 MIB_IPFORWARDROW rowExtant
;
2358 MIB_IPFORWARDROW row
;
2360 ZeroMemory(&row
, sizeof(row
));
2362 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
2363 require_noerr( err
, exit
);
2364 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
2365 row
.dwForwardIfIndex
= ifIndex
;
2366 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
2367 row
.dwForwardType
= 3;
2368 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
2369 row
.dwForwardAge
= 0;
2370 row
.dwForwardPolicy
= 0;
2371 row
.dwForwardMetric1
= 20 + GetAdditionalMetric( ifIndex
);
2372 row
.dwForwardMetric2
= (DWORD
) - 1;
2373 row
.dwForwardMetric3
= (DWORD
) - 1;
2374 row
.dwForwardMetric4
= (DWORD
) - 1;
2375 row
.dwForwardMetric5
= (DWORD
) - 1;
2380 // check to make sure we don't already have a route
2382 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
), 0 ) )
2385 // set the age to 0 so that we can do a memcmp.
2387 rowExtant
.dwForwardAge
= 0;
2390 // check to see if this route is the same as our route
2392 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
2395 // if it isn't then delete this entry
2397 DeleteIpForwardEntry(&rowExtant
);
2402 // else it is, so we don't want to create another route
2408 if (addRoute
&& row
.dwForwardNextHop
)
2410 err
= CreateIpForwardEntry(&row
);
2421 //===========================================================================================================================
2422 // GetRouteDestination
2423 //===========================================================================================================================
2426 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
2429 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
2430 IP_ADAPTER_INFO
* pAdapter
= NULL
;
2432 mDNSBool done
= mDNSfalse
;
2436 // GetBestInterface will fail if there is no default gateway
2437 // configured. If that happens, we will just take the first
2438 // interface in the list. MSDN support says there is no surefire
2439 // way to manually determine what the best interface might
2440 // be for a particular network address.
2442 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
2443 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2451 // Make an initial call to GetAdaptersInfo to get
2452 // the necessary size into the bufLen variable
2454 err
= GetAdaptersInfo( NULL
, &bufLen
);
2455 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2457 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2458 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2460 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2461 require_noerr( err
, exit
);
2463 pAdapter
= pAdapterInfo
;
2466 // <rdar://problem/3718122>
2467 // <rdar://problem/5652098>
2469 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2471 // If these interfaces are active (i.e., has a non-zero IP Address),
2472 // then we want to disable routing table modifications.
2476 if ( ( IsNortelVPN( pAdapter
) || IsJuniperVPN( pAdapter
) || IsCiscoVPN( pAdapter
) ) &&
2477 ( inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0 ) )
2479 dlog( kDebugLevelTrace
, DEBUG_NAME
"disabling routing table management due to VPN incompatibility" );
2483 pAdapter
= pAdapter
->Next
;
2488 pAdapter
= pAdapterInfo
;
2493 // If we don't have an interface selected, choose the first one that is of type ethernet and
2494 // has a valid IP Address
2496 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2498 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2499 *ifIndex
= pAdapter
->Index
;
2504 pAdapter
= pAdapter
->Next
;
2507 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2509 if ( !err
|| !( *ifIndex
) )
2514 // Otherwise, try again by wildcarding the interface
2524 if ( pAdapterInfo
!= NULL
)
2526 free( pAdapterInfo
);
2534 IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
)
2536 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2537 (pAdapter
->AddressLength
== 6) &&
2538 (pAdapter
->Address
[0] == 0x44) &&
2539 (pAdapter
->Address
[1] == 0x45) &&
2540 (pAdapter
->Address
[2] == 0x53) &&
2541 (pAdapter
->Address
[3] == 0x54) &&
2542 (pAdapter
->Address
[4] == 0x42) &&
2543 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2548 IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
)
2550 return ( strnistr( pAdapter
->Description
, "Juniper", sizeof( pAdapter
->Description
) ) != NULL
) ? true : false;
2555 IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
)
2557 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2558 (pAdapter
->AddressLength
== 6) &&
2559 (pAdapter
->Address
[0] == 0x00) &&
2560 (pAdapter
->Address
[1] == 0x05) &&
2561 (pAdapter
->Address
[2] == 0x9a) &&
2562 (pAdapter
->Address
[3] == 0x3c) &&
2563 (pAdapter
->Address
[4] == 0x7a) &&
2564 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2569 strnistr( const char * string
, const char * subString
, size_t max
)
2571 size_t subStringLen
;
2577 if ( ( string
== NULL
) || ( subString
== NULL
) )
2582 stringLen
= ( max
> strlen( string
) ) ? strlen( string
) : max
;
2584 if ( stringLen
== 0 )
2589 subStringLen
= strlen( subString
);
2591 if ( subStringLen
== 0 )
2596 if ( subStringLen
> stringLen
)
2601 maxOffset
= stringLen
- subStringLen
;
2604 for ( offset
= 0; offset
<= maxOffset
; offset
++ )
2606 if ( _strnicmp( pPos
, subString
, subStringLen
) == 0 )