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
;
1193 err
= mDNS_Init( &gMDNSRecord
, &gPlatformStorage
, gRRCache
, RR_CACHE_SIZE
, mDNS_Init_AdvertiseLocalAddresses
, CoreCallback
, mDNS_Init_NoInitCallbackContext
);
1194 require_noerr( err
, exit
);
1196 err
= SetupNotifications();
1199 err
= udsserver_init(mDNSNULL
, 0);
1200 require_noerr( err
, exit
);
1203 // Get the version of Windows that we're running on
1205 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
1206 ok
= GetVersionEx( &osInfo
);
1207 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1208 require_noerr( err
, exit
);
1209 gOSMajorVersion
= osInfo
.dwMajorVersion
;
1210 gOSMinorVersion
= osInfo
.dwMinorVersion
;
1212 SetLLRoute( &gMDNSRecord
);
1217 ServiceSpecificFinalize( argc
, argv
);
1222 //===========================================================================================================================
1223 // ServiceSpecificRun
1224 //===========================================================================================================================
1226 static OSStatus
ServiceSpecificRun( int argc
, LPTSTR argv
[] )
1235 DEBUG_UNUSED( argc
);
1236 DEBUG_UNUSED( argv
);
1238 timeout
= ( gRetryFirewall
) ? kRetryFirewallPeriod
: INFINITE
;
1240 err
= SetupInterfaceList( &gMDNSRecord
);
1243 err
= uDNS_SetupDNSConfig( &gMDNSRecord
);
1255 err
= SetupWaitList( &gMDNSRecord
, &waitList
, &waitListCount
);
1256 require_noerr( err
, exit
);
1258 gEventSourceListChanged
= FALSE
;
1260 while ( !gEventSourceListChanged
)
1262 static mDNSs32 RepeatedBusy
= 0;
1263 mDNSs32 nextTimerEvent
;
1265 // Give the mDNS core a chance to do its work and determine next event time.
1267 nextTimerEvent
= udsserver_idle( mDNS_Execute( &gMDNSRecord
) - mDNS_TimeNow( &gMDNSRecord
) );
1269 if ( nextTimerEvent
< 0) nextTimerEvent
= 0;
1270 else if ( nextTimerEvent
> (0x7FFFFFFF / 1000)) nextTimerEvent
= 0x7FFFFFFF / mDNSPlatformOneSecond
;
1271 else nextTimerEvent
= ( nextTimerEvent
* 1000) / mDNSPlatformOneSecond
;
1273 // Debugging sanity check, to guard against CPU spins
1275 if ( nextTimerEvent
> 0 )
1283 if ( ++RepeatedBusy
>= mDNSPlatformOneSecond
)
1285 ShowTaskSchedulingError( &gMDNSRecord
);
1290 if ( gMDNSRecord
.ShutdownTime
)
1292 mDNSs32 now
= mDNS_TimeNow( &gMDNSRecord
);
1294 if ( mDNS_ExitNow( &gMDNSRecord
, now
) )
1296 mDNS_FinalExit( &gMDNSRecord
);
1301 if ( nextTimerEvent
- gMDNSRecord
.ShutdownTime
>= 0 )
1303 nextTimerEvent
= gMDNSRecord
.ShutdownTime
;
1307 // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
1309 SetSocketEventsEnabled( &gMDNSRecord
, TRUE
);
1310 result
= WaitForMultipleObjectsEx( ( DWORD
) waitListCount
, waitList
, FALSE
, (DWORD
) nextTimerEvent
, TRUE
);
1311 SetSocketEventsEnabled( &gMDNSRecord
, FALSE
);
1312 check( result
!= WAIT_FAILED
);
1314 if ( result
!= WAIT_FAILED
)
1316 if ( result
== WAIT_TIMEOUT
)
1318 // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
1320 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"timeout\n" );
1323 else if ( result
== WAIT_IO_COMPLETION
)
1325 dlog( kDebugLevelChatty
- 1, DEBUG_NAME
"i/o completion\n" );
1328 else if ( result
== kWaitListStopEvent
)
1330 // Stop event. Set the done flag and break to exit.
1332 dlog( kDebugLevelVerbose
, DEBUG_NAME
"stopping...\n" );
1334 mDNS_StartExit( &gMDNSRecord
);
1337 else if( result
== kWaitListInterfaceListChangedEvent
)
1343 // It would be nice to come up with a more elegant solution to this, but it seems that
1344 // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as
1345 // as a simple workaround, we'll pause for a couple of seconds before processing the change.
1347 // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
1348 // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another
1349 // second on top of that to account for machine load or some other exigency.
1353 // Interface list changed event. Break out of the inner loop to re-setup the wait list.
1355 InterfaceListDidChange( &gMDNSRecord
);
1357 // reset the event handler
1360 err
= WSAIoctl( gInterfaceListChangedSocket
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1363 check( errno_compat() == WSAEWOULDBLOCK
);
1366 else if ( result
== kWaitListComputerDescriptionEvent
)
1368 // The computer description might have changed
1370 ComputerDescriptionDidChange( &gMDNSRecord
);
1371 udsserver_handle_configchange( &gMDNSRecord
);
1373 // and reset the event handler
1374 if ( ( gDescKey
!= NULL
) && ( gDescChangedEvent
!= NULL
) )
1376 err
= RegNotifyChangeKeyValue( gDescKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, gDescChangedEvent
, TRUE
);
1380 else if ( result
== kWaitListTCPIPEvent
)
1382 // The TCP/IP might have changed
1384 TCPIPConfigDidChange( &gMDNSRecord
);
1385 udsserver_handle_configchange( &gMDNSRecord
);
1387 // and reset the event handler
1389 if ( ( gTcpipKey
!= NULL
) && ( gTcpipChangedEvent
) )
1391 err
= RegNotifyChangeKeyValue( gTcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gTcpipChangedEvent
, TRUE
);
1395 else if ( result
== kWaitListDynDNSEvent
)
1397 // The DynDNS config might have changed
1399 DynDNSConfigDidChange( &gMDNSRecord
);
1400 udsserver_handle_configchange( &gMDNSRecord
);
1402 // and reset the event handler
1404 if ((gDdnsKey
!= NULL
) && (gDdnsChangedEvent
))
1406 err
= RegNotifyChangeKeyValue(gDdnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gDdnsChangedEvent
, TRUE
);
1410 else if ( result
== kWaitListFileShareEvent
)
1412 // File sharing changed
1414 FileSharingDidChange( &gMDNSRecord
);
1416 // and reset the event handler
1418 if ((gFileSharingKey
!= NULL
) && (gFileSharingChangedEvent
))
1420 err
= RegNotifyChangeKeyValue(gFileSharingKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFileSharingChangedEvent
, TRUE
);
1424 else if ( result
== kWaitListFirewallEvent
)
1426 // Firewall configuration changed
1428 FirewallDidChange( &gMDNSRecord
);
1430 // and reset the event handler
1432 if ((gFirewallKey
!= NULL
) && (gFirewallChangedEvent
))
1434 err
= RegNotifyChangeKeyValue(gFirewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFirewallChangedEvent
, TRUE
);
1438 else if ( result
== kWaitListAdvertisedServicesEvent
)
1440 // Ultimately we'll want to manage multiple services, but right now the only service
1441 // we'll be managing is SMB.
1443 FileSharingDidChange( &gMDNSRecord
);
1445 // and reset the event handler
1447 if ( ( gAdvertisedServicesKey
!= NULL
) && ( gAdvertisedServicesChangedEvent
) )
1449 err
= RegNotifyChangeKeyValue(gAdvertisedServicesKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gAdvertisedServicesChangedEvent
, TRUE
);
1453 else if ( result
== kWaitListSPSWakeupEvent
)
1455 LARGE_INTEGER timeout
;
1457 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Maintenance wake" );
1459 timeout
.QuadPart
= kSPSMaintenanceWakePeriod
;
1460 timeout
.QuadPart
*= kSecondsTo100NSUnits
;
1462 SetWaitableTimer( gSPSSleepEvent
, &timeout
, 0, NULL
, NULL
, TRUE
);
1464 else if ( result
== kWaitListSPSSleepEvent
)
1466 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "Returning to sleep after maintenance wake" );
1468 // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
1469 // call HandlePowerSuspend() explicity. This will reset the
1470 // maintenance wake timers.
1472 HandlePowerSuspend( NULL
);
1473 SetSuspendState( FALSE
, FALSE
, FALSE
);
1479 waitItemIndex
= (int)( ( (int) result
) - WAIT_OBJECT_0
);
1480 dlog( kDebugLevelChatty
, DEBUG_NAME
"waitable event on %d\n", waitItemIndex
);
1481 check( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) );
1483 if ( ( waitItemIndex
>= 0 ) && ( waitItemIndex
< waitListCount
) )
1485 HANDLE signaledEvent
;
1488 signaledEvent
= waitList
[ waitItemIndex
];
1490 // If gCurrentSource is not NULL, then this routine has been called
1491 // re-entrantly which should never happen.
1493 check( !gCurrentSource
);
1495 for ( gCurrentSource
= gEventSourceList
; gCurrentSource
; )
1497 EventSource
* current
= gCurrentSource
;
1499 if ( gCurrentSource
->event
== signaledEvent
)
1501 gCurrentSource
->handler( &gMDNSRecord
, gCurrentSource
->event
, gCurrentSource
->context
);
1506 // If the current node was removed as a result of calling
1507 // the handler, then gCurrentSource was already incremented to
1508 // the next node. If it wasn't removed, then increment it
1511 if ( gCurrentSource
== current
)
1513 gCurrentSource
= gCurrentSource
->next
;
1517 gCurrentSource
= NULL
;
1523 dlog( kDebugLevelWarning
, DEBUG_NAME
"%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__
, result
);
1531 err
= SetupInterfaceList( &gMDNSRecord
);
1534 err
= uDNS_SetupDNSConfig( &gMDNSRecord
);
1554 //===========================================================================================================================
1555 // ServiceSpecificStop
1556 //===========================================================================================================================
1558 static OSStatus
ServiceSpecificStop( void )
1563 ok
= SetEvent(gStopEvent
);
1564 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
1565 require_noerr( err
, exit
);
1570 //===========================================================================================================================
1571 // ServiceSpecificFinalize
1572 //===========================================================================================================================
1574 static void ServiceSpecificFinalize( int argc
, LPTSTR argv
[] )
1576 DEBUG_UNUSED( argc
);
1577 DEBUG_UNUSED( argv
);
1580 // clean up any open sessions
1582 while ( gEventSourceList
)
1584 UnregisterWaitableEvent( &gMDNSRecord
, gEventSourceList
->event
);
1588 // clean up the notifications
1590 TearDownNotifications();
1593 // clean up loaded library
1596 if( gIPHelperLibraryInstance
)
1598 gGetIpInterfaceEntryFunctionPtr
= NULL
;
1600 FreeLibrary( gIPHelperLibraryInstance
);
1601 gIPHelperLibraryInstance
= NULL
;
1606 //===========================================================================================================================
1607 // SetupNotifications
1608 //===========================================================================================================================
1610 mDNSlocal mStatus
SetupNotifications()
1614 unsigned long param
;
1619 gStopEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1620 err
= translate_errno( gStopEvent
, errno_compat(), kNoResourcesErr
);
1621 require_noerr( err
, exit
);
1623 // Register to listen for address list changes.
1625 gInterfaceListChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1626 err
= translate_errno( gInterfaceListChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1627 require_noerr( err
, exit
);
1629 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1630 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
1631 require_noerr( err
, exit
);
1632 gInterfaceListChangedSocket
= sock
;
1634 // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
1635 // when a change to the interface list is detected.
1638 err
= ioctlsocket( sock
, FIONBIO
, ¶m
);
1639 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
1640 require_noerr( err
, exit
);
1644 err
= WSAIoctl( sock
, SIO_ADDRESS_LIST_CHANGE
, &inBuffer
, 0, &outBuffer
, 0, &outSize
, NULL
, NULL
);
1647 check( errno_compat() == WSAEWOULDBLOCK
);
1650 err
= WSAEventSelect( sock
, gInterfaceListChangedEvent
, FD_ADDRESS_LIST_CHANGE
);
1651 err
= translate_errno( err
== 0, errno_compat(), kUnknownErr
);
1652 require_noerr( err
, exit
);
1654 gDescChangedEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
1655 err
= translate_errno( gDescChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1656 require_noerr( err
, exit
);
1658 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ
, &gDescKey
);
1659 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
1661 if ( gDescKey
!= NULL
)
1663 err
= RegNotifyChangeKeyValue( gDescKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, gDescChangedEvent
, TRUE
);
1664 require_noerr( err
, exit
);
1667 // This will catch all changes to tcp/ip networking, including changes to the domain search list
1669 gTcpipChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1670 err
= translate_errno( gTcpipChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1671 require_noerr( err
, exit
);
1673 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey
);
1674 require_noerr( err
, exit
);
1676 err
= RegNotifyChangeKeyValue( gTcpipKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gTcpipChangedEvent
, TRUE
);
1677 require_noerr( err
, exit
);
1679 // This will catch all changes to ddns configuration
1681 gDdnsChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1682 err
= translate_errno( gDdnsChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1683 require_noerr( err
, exit
);
1685 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup"), &gDdnsKey
);
1686 require_noerr( err
, exit
);
1688 err
= RegNotifyChangeKeyValue( gDdnsKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gDdnsChangedEvent
, TRUE
);
1689 require_noerr( err
, exit
);
1691 // This will catch all changes to file sharing
1693 gFileSharingChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1694 err
= translate_errno( gFileSharingChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1695 require_noerr( err
, exit
);
1697 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey
);
1699 // Just to make sure that initialization doesn't fail on some old OS
1700 // that doesn't have this key, we'll only add the notification if
1705 err
= RegNotifyChangeKeyValue( gFileSharingKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFileSharingChangedEvent
, TRUE
);
1706 require_noerr( err
, exit
);
1710 err
= mStatus_NoError
;
1713 // This will catch changes to the Windows firewall
1715 gFirewallChangedEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1716 err
= translate_errno( gFirewallChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1717 require_noerr( err
, exit
);
1719 // Just to make sure that initialization doesn't fail on some old OS
1720 // that doesn't have this key, we'll only add the notification if
1723 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey
);
1727 err
= RegNotifyChangeKeyValue( gFirewallKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gFirewallChangedEvent
, TRUE
);
1728 require_noerr( err
, exit
);
1732 err
= mStatus_NoError
;
1735 // This will catch all changes to advertised services configuration
1737 gAdvertisedServicesChangedEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1738 err
= translate_errno( gAdvertisedServicesChangedEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1739 require_noerr( err
, exit
);
1741 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\Services"), &gAdvertisedServicesKey
);
1742 require_noerr( err
, exit
);
1744 err
= RegNotifyChangeKeyValue( gAdvertisedServicesKey
, TRUE
, REG_NOTIFY_CHANGE_NAME
|REG_NOTIFY_CHANGE_LAST_SET
, gAdvertisedServicesChangedEvent
, TRUE
);
1745 require_noerr( err
, exit
);
1747 gSPSWakeupEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1748 err
= translate_errno( gSPSWakeupEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1749 require_noerr( err
, exit
);
1751 gSPSSleepEvent
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
1752 err
= translate_errno( gSPSSleepEvent
, (mStatus
) GetLastError(), kUnknownErr
);
1753 require_noerr( err
, exit
);
1755 gUDSEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1756 err
= translate_errno( gUDSEvent
, ( mStatus
) GetLastError(), kUnknownErr
);
1757 require_noerr( err
, exit
);
1762 TearDownNotifications();
1767 //===========================================================================================================================
1768 // TearDownNotifications
1769 //===========================================================================================================================
1771 mDNSlocal mStatus
TearDownNotifications()
1775 CloseHandle( gStopEvent
);
1779 if( IsValidSocket( gInterfaceListChangedSocket
) )
1781 close_compat( gInterfaceListChangedSocket
);
1782 gInterfaceListChangedSocket
= kInvalidSocketRef
;
1785 if( gInterfaceListChangedEvent
)
1787 CloseHandle( gInterfaceListChangedEvent
);
1788 gInterfaceListChangedEvent
= 0;
1791 if ( gDescChangedEvent
!= NULL
)
1793 CloseHandle( gDescChangedEvent
);
1794 gDescChangedEvent
= NULL
;
1797 if ( gDescKey
!= NULL
)
1799 RegCloseKey( gDescKey
);
1803 if ( gTcpipChangedEvent
!= NULL
)
1805 CloseHandle( gTcpipChangedEvent
);
1806 gTcpipChangedEvent
= NULL
;
1809 if ( gDdnsChangedEvent
!= NULL
)
1811 CloseHandle( gDdnsChangedEvent
);
1812 gDdnsChangedEvent
= NULL
;
1815 if ( gDdnsKey
!= NULL
)
1817 RegCloseKey( gDdnsKey
);
1821 if ( gFileSharingChangedEvent
!= NULL
)
1823 CloseHandle( gFileSharingChangedEvent
);
1824 gFileSharingChangedEvent
= NULL
;
1827 if ( gFileSharingKey
!= NULL
)
1829 RegCloseKey( gFileSharingKey
);
1830 gFileSharingKey
= NULL
;
1833 if ( gFirewallChangedEvent
!= NULL
)
1835 CloseHandle( gFirewallChangedEvent
);
1836 gFirewallChangedEvent
= NULL
;
1839 if ( gFirewallKey
!= NULL
)
1841 RegCloseKey( gFirewallKey
);
1842 gFirewallKey
= NULL
;
1845 if ( gAdvertisedServicesChangedEvent
!= NULL
)
1847 CloseHandle( gAdvertisedServicesChangedEvent
);
1848 gAdvertisedServicesChangedEvent
= NULL
;
1851 if ( gAdvertisedServicesKey
!= NULL
)
1853 RegCloseKey( gAdvertisedServicesKey
);
1854 gAdvertisedServicesKey
= NULL
;
1857 if ( gSPSWakeupEvent
)
1859 CloseHandle( gSPSWakeupEvent
);
1860 gSPSWakeupEvent
= NULL
;
1863 if ( gSPSSleepEvent
)
1865 CloseHandle( gSPSSleepEvent
);
1866 gSPSSleepEvent
= NULL
;
1869 return( mStatus_NoError
);
1873 //===========================================================================================================================
1874 // RegisterWaitableEvent
1875 //===========================================================================================================================
1877 static mStatus
RegisterWaitableEvent( mDNS
* const inMDNS
, HANDLE event
, void * context
, RegisterWaitableEventHandler handler
)
1879 EventSource
* source
;
1880 mStatus err
= mStatus_NoError
;
1886 source
= ( EventSource
* ) malloc( sizeof( EventSource
) );
1887 require_action( source
, exit
, err
= mStatus_NoMemoryErr
);
1888 mDNSPlatformMemZero( source
, sizeof( EventSource
) );
1889 source
->event
= event
;
1890 source
->context
= context
;
1891 source
->handler
= handler
;
1893 source
->next
= gEventSourceList
;
1894 gEventSourceList
= source
;
1895 gEventSourceListChanged
= TRUE
;
1904 //===========================================================================================================================
1905 // UnregisterWaitableEvent
1906 //===========================================================================================================================
1908 static void UnregisterWaitableEvent( mDNS
* const inMDNS
, HANDLE event
)
1910 EventSource
* current
= gEventSourceList
;
1911 EventSource
* last
= NULL
;
1918 if ( current
->event
== event
)
1922 gEventSourceList
= current
->next
;
1926 last
->next
= current
->next
;
1929 gEventSourceListChanged
= TRUE
;
1931 // Protect against removing the node that we happen
1932 // to be looking at as we iterate through the event
1933 // source list in ServiceSpecificRun()
1935 if ( current
== gCurrentSource
)
1937 gCurrentSource
= current
->next
;
1947 current
= current
->next
;
1952 //===========================================================================================================================
1954 //===========================================================================================================================
1956 mDNSlocal mStatus
SetupWaitList( mDNS
* const inMDNS
, HANDLE
**outWaitList
, int *outWaitListCount
)
1960 HANDLE
* waitItemPtr
;
1961 EventSource
* source
;
1964 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up wait list\n" );
1968 check( outWaitList
);
1969 check( outWaitListCount
);
1971 // Allocate an array to hold all the objects to wait on.
1973 waitListCount
= kWaitListFixedItemCount
+ gEventSources
;
1974 waitList
= ( HANDLE
* ) malloc( waitListCount
* sizeof( *waitList
) );
1975 require_action( waitList
, exit
, err
= mStatus_NoMemoryErr
);
1976 waitItemPtr
= waitList
;
1978 // Add the fixed wait items to the beginning of the list.
1980 *waitItemPtr
++ = gStopEvent
;
1981 *waitItemPtr
++ = gInterfaceListChangedEvent
;
1982 *waitItemPtr
++ = gDescChangedEvent
;
1983 *waitItemPtr
++ = gTcpipChangedEvent
;
1984 *waitItemPtr
++ = gDdnsChangedEvent
;
1985 *waitItemPtr
++ = gFileSharingChangedEvent
;
1986 *waitItemPtr
++ = gFirewallChangedEvent
;
1987 *waitItemPtr
++ = gAdvertisedServicesChangedEvent
;
1988 *waitItemPtr
++ = gSPSWakeupEvent
;
1989 *waitItemPtr
++ = gSPSSleepEvent
;
1991 for ( source
= gEventSourceList
; source
; source
= source
->next
)
1993 *waitItemPtr
++ = source
->event
;
1996 check( ( int )( waitItemPtr
- waitList
) == waitListCount
);
1998 *outWaitList
= waitList
;
1999 *outWaitListCount
= waitListCount
;
2001 err
= mStatus_NoError
;
2010 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up wait list done (err=%d %m)\n", err
, err
);
2015 //===========================================================================================================================
2017 //===========================================================================================================================
2020 CoreCallback(mDNS
* const inMDNS
, mStatus status
)
2022 if (status
== mStatus_ConfigChanged
)
2024 SetLLRoute( inMDNS
);
2029 //===========================================================================================================================
2031 //===========================================================================================================================
2033 mDNSlocal
void UDSCanAccept( mDNS
* const inMDNS
, HANDLE event
, void * context
)
2040 gUDSCallback( ( int ) gUDSSocket
, 0, context
);
2045 //===========================================================================================================================
2047 //===========================================================================================================================
2049 mDNSlocal
void UDSCanRead( TCPSocket
* sock
)
2051 udsEventCallback callback
= ( udsEventCallback
) sock
->userCallback
;
2055 callback( (int) sock
->fd
, 0, sock
->userContext
);
2060 //===========================================================================================================================
2061 // udsSupportAddFDToEventLoop
2062 //===========================================================================================================================
2065 udsSupportAddFDToEventLoop( SocketRef fd
, udsEventCallback callback
, void *context
, void **platform_data
)
2067 mStatus err
= mStatus_NoError
;
2069 // We are using some knowledge of what is being passed to us here. If the fd is a listen socket,
2070 // then the "callback" parameter is NULL. If it is an actual read/write socket, then the "callback"
2071 // parameter is not null. This is important because we use waitable events for the listen socket
2072 // and alertable I/O for the read/write sockets.
2078 sock
= malloc( sizeof( TCPSocket
) );
2079 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
2080 mDNSPlatformMemZero( sock
, sizeof( TCPSocket
) );
2082 sock
->fd
= (SOCKET
) fd
;
2083 sock
->readEventHandler
= UDSCanRead
;
2084 sock
->userCallback
= callback
;
2085 sock
->userContext
= context
;
2086 sock
->m
= &gMDNSRecord
;
2088 err
= TCPAddSocket( sock
->m
, sock
);
2089 require_noerr( err
, exit
);
2091 *platform_data
= sock
;
2096 gUDSCallback
= callback
;
2097 gUDSEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
2098 err
= translate_errno( gUDSEvent
, (mStatus
) GetLastError(), kUnknownErr
);
2099 require_noerr( err
, exit
);
2100 err
= WSAEventSelect( fd
, gUDSEvent
, FD_ACCEPT
| FD_CLOSE
);
2101 err
= translate_errno( err
== 0, WSAGetLastError(), kNoResourcesErr
);
2102 require_noerr( err
, exit
);
2103 err
= RegisterWaitableEvent( &gMDNSRecord
, gUDSEvent
, context
, UDSCanAccept
);
2104 require_noerr( err
, exit
);
2114 udsSupportReadFD( SocketRef fd
, char *buf
, int len
, int flags
, void *platform_data
)
2122 sock
= ( TCPSocket
* ) platform_data
;
2123 require_action( sock
, exit
, ret
= -1 );
2124 require_action( sock
->fd
== fd
, exit
, ret
= -1 );
2126 ret
= mDNSPlatformReadTCP( sock
, buf
, len
, &closed
);
2140 udsSupportRemoveFDFromEventLoop( SocketRef fd
, void *platform_data
) // Note: This also CLOSES the socket
2142 mStatus err
= kNoErr
;
2144 if ( platform_data
!= NULL
)
2148 dlog( kDebugLevelInfo
, DEBUG_NAME
"session closed\n" );
2149 sock
= ( TCPSocket
* ) platform_data
;
2150 check( sock
->fd
== fd
);
2151 mDNSPlatformTCPCloseConnection( sock
);
2153 else if ( gUDSEvent
!= NULL
)
2155 UnregisterWaitableEvent( &gMDNSRecord
, gUDSEvent
);
2156 WSAEventSelect( fd
, gUDSEvent
, 0 );
2157 CloseHandle( gUDSEvent
);
2165 mDNSexport
void RecordUpdatedNiceLabel(mDNS
*const m
, mDNSs32 delay
)
2173 //===========================================================================================================================
2174 // SystemWakeForNetworkAccess
2175 //===========================================================================================================================
2178 SystemWakeForNetworkAccess( LARGE_INTEGER
* timeout
)
2184 SYSTEM_POWER_STATUS powerStatus
;
2186 time_t nextWakeupTime
;
2190 dlog( kDebugLevelInfo
, DEBUG_NAME
"SystemWakeForNetworkAccess\n" );
2192 // Make sure we have a timer
2194 require_action( gSPSWakeupEvent
!= NULL
, exit
, ok
= FALSE
);
2195 require_action( gSPSSleepEvent
!= NULL
, exit
, ok
= FALSE
);
2197 // Make sure the user enabled bonjour sleep proxy client
2199 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\Power Management", &key
);
2200 require_action( !err
, exit
, ok
= FALSE
);
2201 dwSize
= sizeof( DWORD
);
2202 err
= RegQueryValueEx( key
, L
"Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
2203 require_action( !err
, exit
, ok
= FALSE
);
2204 require_action( enabled
, exit
, ok
= FALSE
);
2206 // Make sure machine is on AC power
2208 ok
= ( mDNSu8
) GetSystemPowerStatus( &powerStatus
);
2209 require_action( ok
, exit
, ok
= FALSE
);
2210 require_action( powerStatus
.ACLineStatus
== AC_LINE_ONLINE
, exit
, ok
= FALSE
);
2212 // Now make sure we have a network interface that does wake-on-lan
2214 ok
= ( mDNSu8
) IsWOMPEnabled( &gMDNSRecord
);
2215 require_action( ok
, exit
, ok
= FALSE
);
2217 // Now make sure we have advertised services. Doesn't make sense to
2218 // enable sleep proxy if we have no multicast services that could
2219 // potentially wake us up.
2221 ok
= ( mDNSu8
) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord
);
2222 require_action( ok
, exit
, ok
= FALSE
);
2224 // Calculate next wake up time
2226 startTime
= time( NULL
); // Seconds since midnight January 1, 1970
2227 nextWakeupTime
= startTime
+ ( 120 * 60 ); // 2 hours later
2229 if ( gMDNSRecord
.p
->nextDHCPLeaseExpires
< nextWakeupTime
)
2231 nextWakeupTime
= gMDNSRecord
.p
->nextDHCPLeaseExpires
;
2234 // Finally calculate the next relative wakeup time
2236 delta
= ( int )( ( ( double )( nextWakeupTime
- startTime
) ) * 0.9 );
2237 ReportStatus( EVENTLOG_INFORMATION_TYPE
, "enabling sleep proxy client with next maintenance wake in %d seconds", delta
);
2239 // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
2241 timeout
->QuadPart
= -delta
;
2242 timeout
->QuadPart
*= kSecondsTo100NSUnits
;
2257 //===========================================================================================================================
2259 //===========================================================================================================================
2262 HaveRoute( PMIB_IPFORWARDROW rowExtant
, unsigned long addr
, unsigned long metric
)
2264 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
2266 BOOL bOrder
= FALSE
;
2269 unsigned long int i
;
2272 // Find out how big our buffer needs to be.
2274 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
2275 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
2278 // Allocate the memory for the table
2280 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
2281 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
2284 // Now get the table.
2286 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
2287 require_noerr( err
, exit
);
2290 // Search for the row in the table we want.
2292 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
2294 if ( ( pIpForwardTable
->table
[i
].dwForwardDest
== addr
) && ( !metric
|| ( pIpForwardTable
->table
[i
].dwForwardMetric1
== metric
) ) )
2296 memcpy( rowExtant
, &(pIpForwardTable
->table
[i
]), sizeof(*rowExtant
) );
2304 if ( pIpForwardTable
!= NULL
)
2306 free(pIpForwardTable
);
2313 //===========================================================================================================================
2315 //===========================================================================================================================
2318 IsValidAddress( const char * addr
)
2320 return ( addr
&& ( strcmp( addr
, "0.0.0.0" ) != 0 ) ) ? true : false;
2324 //===========================================================================================================================
2325 // GetAdditionalMetric
2326 //===========================================================================================================================
2329 GetAdditionalMetric( DWORD ifIndex
)
2333 if( !gIPHelperLibraryInstance
)
2335 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
2337 gGetIpInterfaceEntryFunctionPtr
=
2338 (GetIpInterfaceEntryFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetIpInterfaceEntry" );
2340 if( !gGetIpInterfaceEntryFunctionPtr
)
2344 ok
= FreeLibrary( gIPHelperLibraryInstance
);
2345 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
2346 gIPHelperLibraryInstance
= NULL
;
2350 if ( gGetIpInterfaceEntryFunctionPtr
)
2352 MIB_IPINTERFACE_ROW row
;
2355 ZeroMemory( &row
, sizeof( MIB_IPINTERFACE_ROW
) );
2356 row
.Family
= AF_INET
;
2357 row
.InterfaceIndex
= ifIndex
;
2358 err
= gGetIpInterfaceEntryFunctionPtr( &row
);
2359 require_noerr( err
, exit
);
2360 metric
= row
.Metric
+ 256;
2369 //===========================================================================================================================
2371 //===========================================================================================================================
2374 SetLLRoute( mDNS
* const inMDNS
)
2376 OSStatus err
= kNoErr
;
2378 DEBUG_UNUSED( inMDNS
);
2381 // <rdar://problem/4096464> Don't call SetLLRoute on loopback
2382 // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
2384 // Don't mess w/ the routing table on Vista and later OSes, as
2385 // they have a permanent route to link-local addresses. Otherwise,
2386 // set a route to link local addresses (169.254.0.0)
2388 if ( ( gOSMajorVersion
< 6 ) && gServiceManageLLRouting
&& !gPlatformStorage
.registeredLoopback4
)
2391 MIB_IPFORWARDROW rowExtant
;
2393 MIB_IPFORWARDROW row
;
2395 ZeroMemory(&row
, sizeof(row
));
2397 err
= GetRouteDestination(&ifIndex
, &row
.dwForwardNextHop
);
2398 require_noerr( err
, exit
);
2399 row
.dwForwardDest
= inet_addr(kLLNetworkAddr
);
2400 row
.dwForwardIfIndex
= ifIndex
;
2401 row
.dwForwardMask
= inet_addr(kLLNetworkAddrMask
);
2402 row
.dwForwardType
= 3;
2403 row
.dwForwardProto
= MIB_IPPROTO_NETMGMT
;
2404 row
.dwForwardAge
= 0;
2405 row
.dwForwardPolicy
= 0;
2406 row
.dwForwardMetric1
= 20 + GetAdditionalMetric( ifIndex
);
2407 row
.dwForwardMetric2
= (DWORD
) - 1;
2408 row
.dwForwardMetric3
= (DWORD
) - 1;
2409 row
.dwForwardMetric4
= (DWORD
) - 1;
2410 row
.dwForwardMetric5
= (DWORD
) - 1;
2415 // check to make sure we don't already have a route
2417 if ( HaveRoute( &rowExtant
, inet_addr( kLLNetworkAddr
), 0 ) )
2420 // set the age to 0 so that we can do a memcmp.
2422 rowExtant
.dwForwardAge
= 0;
2425 // check to see if this route is the same as our route
2427 if (memcmp(&row
, &rowExtant
, sizeof(row
)) != 0)
2430 // if it isn't then delete this entry
2432 DeleteIpForwardEntry(&rowExtant
);
2437 // else it is, so we don't want to create another route
2443 if (addRoute
&& row
.dwForwardNextHop
)
2445 err
= CreateIpForwardEntry(&row
);
2456 //===========================================================================================================================
2457 // GetRouteDestination
2458 //===========================================================================================================================
2461 GetRouteDestination(DWORD
* ifIndex
, DWORD
* address
)
2464 IP_ADAPTER_INFO
* pAdapterInfo
= NULL
;
2465 IP_ADAPTER_INFO
* pAdapter
= NULL
;
2467 mDNSBool done
= mDNSfalse
;
2471 // GetBestInterface will fail if there is no default gateway
2472 // configured. If that happens, we will just take the first
2473 // interface in the list. MSDN support says there is no surefire
2474 // way to manually determine what the best interface might
2475 // be for a particular network address.
2477 ia
.s_addr
= inet_addr(kLLNetworkAddr
);
2478 err
= GetBestInterface(*(IPAddr
*) &ia
, ifIndex
);
2486 // Make an initial call to GetAdaptersInfo to get
2487 // the necessary size into the bufLen variable
2489 err
= GetAdaptersInfo( NULL
, &bufLen
);
2490 require_action( err
== ERROR_BUFFER_OVERFLOW
, exit
, err
= kUnknownErr
);
2492 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc( bufLen
);
2493 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2495 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2496 require_noerr( err
, exit
);
2498 pAdapter
= pAdapterInfo
;
2501 // <rdar://problem/3718122>
2502 // <rdar://problem/5652098>
2504 // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
2506 // If these interfaces are active (i.e., has a non-zero IP Address),
2507 // then we want to disable routing table modifications.
2511 if ( ( IsNortelVPN( pAdapter
) || IsJuniperVPN( pAdapter
) || IsCiscoVPN( pAdapter
) ) &&
2512 ( inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
) != 0 ) )
2514 dlog( kDebugLevelTrace
, DEBUG_NAME
"disabling routing table management due to VPN incompatibility" );
2518 pAdapter
= pAdapter
->Next
;
2523 pAdapter
= pAdapterInfo
;
2528 // If we don't have an interface selected, choose the first one that is of type ethernet and
2529 // has a valid IP Address
2531 if ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) && ( IsValidAddress( pAdapter
->IpAddressList
.IpAddress
.String
) ) && (!(*ifIndex
) || (pAdapter
->Index
== (*ifIndex
))))
2533 *address
= inet_addr( pAdapter
->IpAddressList
.IpAddress
.String
);
2534 *ifIndex
= pAdapter
->Index
;
2539 pAdapter
= pAdapter
->Next
;
2542 // If we found the right interface, or we weren't trying to find a specific interface then we're done
2544 if ( !err
|| !( *ifIndex
) )
2549 // Otherwise, try again by wildcarding the interface
2559 if ( pAdapterInfo
!= NULL
)
2561 free( pAdapterInfo
);
2569 IsNortelVPN( IP_ADAPTER_INFO
* pAdapter
)
2571 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2572 (pAdapter
->AddressLength
== 6) &&
2573 (pAdapter
->Address
[0] == 0x44) &&
2574 (pAdapter
->Address
[1] == 0x45) &&
2575 (pAdapter
->Address
[2] == 0x53) &&
2576 (pAdapter
->Address
[3] == 0x54) &&
2577 (pAdapter
->Address
[4] == 0x42) &&
2578 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2583 IsJuniperVPN( IP_ADAPTER_INFO
* pAdapter
)
2585 return ( strnistr( pAdapter
->Description
, "Juniper", sizeof( pAdapter
->Description
) ) != NULL
) ? true : false;
2590 IsCiscoVPN( IP_ADAPTER_INFO
* pAdapter
)
2592 return ((pAdapter
->Type
== MIB_IF_TYPE_ETHERNET
) &&
2593 (pAdapter
->AddressLength
== 6) &&
2594 (pAdapter
->Address
[0] == 0x00) &&
2595 (pAdapter
->Address
[1] == 0x05) &&
2596 (pAdapter
->Address
[2] == 0x9a) &&
2597 (pAdapter
->Address
[3] == 0x3c) &&
2598 (pAdapter
->Address
[4] == 0x7a) &&
2599 (pAdapter
->Address
[5] == 0x00)) ? true : false;
2604 strnistr( const char * string
, const char * subString
, size_t max
)
2606 size_t subStringLen
;
2612 if ( ( string
== NULL
) || ( subString
== NULL
) )
2617 stringLen
= ( max
> strlen( string
) ) ? strlen( string
) : max
;
2619 if ( stringLen
== 0 )
2624 subStringLen
= strlen( subString
);
2626 if ( subStringLen
== 0 )
2631 if ( subStringLen
> stringLen
)
2636 maxOffset
= stringLen
- subStringLen
;
2639 for ( offset
= 0; offset
<= maxOffset
; offset
++ )
2641 if ( _strnicmp( pPos
, subString
, subStringLen
) == 0 )