Home | History | Annotate | Download | only in SystemService
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
      4  *
      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
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     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.
     16  */
     17 
     18 #include	<stdio.h>
     19 #include	<stdlib.h>
     20 #include	<crtdbg.h>
     21 #include	<stdarg.h>
     22 #include	<stddef.h>
     23 
     24 
     25 #include	"CommonServices.h"
     26 #include	"DebugServices.h"
     27 #include	"RegNames.h"
     28 
     29 #include	"uds_daemon.h"
     30 #include	"GenLinkedList.h"
     31 #include	"Service.h"
     32 #include	"mDNSWindows/SystemService/EventLog.h"
     33 
     34 #include	"Resource.h"
     35 
     36 #include	"mDNSEmbeddedAPI.h"
     37 #include	"uDNS.h"
     38 #include	"mDNSWin32.h"
     39 
     40 #include	"Firewall.h"
     41 
     42 #if( !TARGET_OS_WINDOWS_CE )
     43 	#include	<mswsock.h>
     44 	#include	<process.h>
     45 	#include	<ipExport.h>
     46 	#include	<ws2def.h>
     47 	#include	<ws2ipdef.h>
     48 	#include	<iphlpapi.h>
     49 	#include	<netioapi.h>
     50 	#include	<iptypes.h>
     51 	#include	<powrprof.h>
     52 #endif
     53 
     54 #ifndef HeapEnableTerminationOnCorruption
     55 #	define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
     56 #endif
     57 
     58 #if 0
     59 #pragma mark == Constants ==
     60 #endif
     61 
     62 //===========================================================================================================================
     63 //	Constants
     64 //===========================================================================================================================
     65 
     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
     72 #define kZeroIndex							0
     73 #define kDefaultRouteMetric					399
     74 #define kSecondsTo100NSUnits				( 10 * 1000 * 1000 )
     75 #define kSPSMaintenanceWakePeriod			-30
     76 
     77 #define RR_CACHE_SIZE 500
     78 static CacheEntity gRRCache[RR_CACHE_SIZE];
     79 #if 0
     80 #pragma mark == Structures ==
     81 #endif
     82 
     83 //===========================================================================================================================
     84 //	Structures
     85 //===========================================================================================================================
     86 
     87 typedef struct EventSource
     88 {
     89 	HANDLE							event;
     90 	void						*	context;
     91 	RegisterWaitableEventHandler	handler;
     92 	struct EventSource			*	next;
     93 } EventSource;
     94 
     95 static BOOL											gEventSourceListChanged = FALSE;
     96 static EventSource								*	gEventSourceList = NULL;
     97 static EventSource								*	gCurrentSource = NULL;
     98 static int											gEventSources = 0;
     99 
    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
    111 
    112 
    113 #if 0
    114 #pragma mark == Prototypes ==
    115 #endif
    116 
    117 //===========================================================================================================================
    118 //	Prototypes
    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, ... );
    129 
    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 );
    133 
    134 static OSStatus		ServiceRun( int argc, LPTSTR argv[] );
    135 static void			ServiceStop( void );
    136 
    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 );
    160 
    161 #if defined(UNICODE)
    162 #	define StrLen(X)	wcslen(X)
    163 #	define StrCmp(X,Y)	wcscmp(X,Y)
    164 #else
    165 #	define StrLen(X)	strlen(X)
    166 #	define StrCmp(X,Y)	strcmp(X,Y)
    167 #endif
    168 
    169 
    170 #define kLLNetworkAddr      "169.254.0.0"
    171 #define kLLNetworkAddrMask  "255.255.0.0"
    172 
    173 
    174 #include	"mDNSEmbeddedAPI.h"
    175 
    176 #if 0
    177 #pragma mark == Globals ==
    178 #endif
    179 
    180 //===========================================================================================================================
    181 //	Globals
    182 //===========================================================================================================================
    183 #define gMDNSRecord mDNSStorage
    184 DEBUG_LOCAL	mDNS_PlatformSupport		gPlatformStorage;
    185 DEBUG_LOCAL BOOL						gServiceQuietMode		= FALSE;
    186 DEBUG_LOCAL SERVICE_TABLE_ENTRY			gServiceDispatchTable[] =
    187 {
    188 	{ kServiceName,	ServiceMain },
    189 	{ NULL, 		NULL }
    190 };
    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;
    222 
    223 typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
    224 mDNSlocal HMODULE								gIPHelperLibraryInstance		= NULL;
    225 mDNSlocal GetIpInterfaceEntryFunctionPtr		gGetIpInterfaceEntryFunctionPtr	= NULL;
    226 
    227 
    228 #if 0
    229 #pragma mark -
    230 #endif
    231 
    232 //===========================================================================================================================
    233 //	Main
    234 //===========================================================================================================================
    235 int	Main( int argc, LPTSTR argv[] )
    236 {
    237 	OSStatus		err;
    238 	BOOL			ok;
    239 	BOOL			start;
    240 	int				i;
    241 
    242 	HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
    243 
    244 	debug_initialize( kDebugOutputTypeMetaConsole );
    245 	debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
    246 
    247 	// Default to automatically starting the service dispatcher if no extra arguments are specified.
    248 
    249 	start = ( argc <= 1 );
    250 
    251 	// Parse arguments.
    252 
    253 	for( i = 1; i < argc; ++i )
    254 	{
    255 		if( StrCmp( argv[ i ], TEXT("-install") ) == 0 )			// Install
    256 		{
    257 			TCHAR desc[ 256 ];
    258 
    259 			desc[ 0 ] = 0;
    260 			LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
    261 			err = InstallService( kServiceName, kServiceName, desc, argv[0] );
    262 			if( err )
    263 			{
    264 				ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
    265 				goto exit;
    266 			}
    267 		}
    268 		else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 )		// Remove
    269 		{
    270 			err = RemoveService( kServiceName );
    271 			if( err )
    272 			{
    273 				ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
    274 				goto exit;
    275 			}
    276 		}
    277 		else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 )		// Start
    278 		{
    279 			start = TRUE;
    280 		}
    281 		else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 )		// Server
    282 		{
    283 			err = RunDirect( argc, argv );
    284 			if( err )
    285 			{
    286 				ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
    287 			}
    288 			goto exit;
    289 		}
    290 		else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 )			// Quiet Mode (toggle)
    291 		{
    292 			gServiceQuietMode = !gServiceQuietMode;
    293 		}
    294 		else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) || 	// Help
    295 				 ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
    296 		{
    297 			Usage();
    298 			err = 0;
    299 			break;
    300 		}
    301 		else
    302 		{
    303 			Usage();
    304 			err = kParamErr;
    305 			break;
    306 		}
    307 	}
    308 
    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.
    312 
    313 	if( start )
    314 	{
    315 		ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
    316 		err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
    317 		if( err != kNoErr )
    318 		{
    319 			ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
    320 			goto exit;
    321 		}
    322 	}
    323 	err = 0;
    324 
    325 exit:
    326 	dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
    327 	_CrtDumpMemoryLeaks();
    328 	return( (int) err );
    329 }
    330 
    331 //===========================================================================================================================
    332 //	Usage
    333 //===========================================================================================================================
    334 
    335 static void	Usage( void )
    336 {
    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" );
    350 }
    351 
    352 //===========================================================================================================================
    353 //	ConsoleControlHandler
    354 //===========================================================================================================================
    355 
    356 static BOOL WINAPI	ConsoleControlHandler( DWORD inControlEvent )
    357 {
    358 	BOOL			handled;
    359 	OSStatus		err;
    360 
    361 	handled = FALSE;
    362 	switch( inControlEvent )
    363 	{
    364 		case CTRL_C_EVENT:
    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 );
    371 
    372 			handled = TRUE;
    373 			break;
    374 
    375 		default:
    376 			break;
    377 	}
    378 
    379 exit:
    380 	return( handled );
    381 }
    382 
    383 //===========================================================================================================================
    384 //	InstallService
    385 //===========================================================================================================================
    386 
    387 static OSStatus	InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
    388 {
    389 	OSStatus		err;
    390 	SC_HANDLE		scm;
    391 	SC_HANDLE		service;
    392 	BOOL			ok;
    393 	TCHAR			fullPath[ MAX_PATH ];
    394 	TCHAR *			namePtr;
    395 	DWORD			size;
    396 
    397 	scm		= NULL;
    398 	service = NULL;
    399 
    400 	// Get a full path to the executable since a relative path may have been specified.
    401 
    402 	size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
    403 	err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
    404 	require_noerr( err, exit );
    405 
    406 	// Create the service and start it.
    407 
    408 	scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    409 	err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
    410 	require_noerr( err, exit );
    411 
    412 	service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS,
    413 							 SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies,
    414 							 NULL, NULL );
    415 	err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
    416 	require_noerr( err, exit );
    417 
    418 	err = SetServiceParameters();
    419 	check_noerr( err );
    420 
    421 	if( inDescription )
    422 	{
    423 		err = SetServiceInfo( scm, inName, inDescription );
    424 		check_noerr( err );
    425 	}
    426 
    427 	ok = StartService( service, 0, NULL );
    428 	err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
    429 	require_noerr( err, exit );
    430 
    431 	ReportStatus( EVENTLOG_SUCCESS, "installed service\n" );
    432 	err = kNoErr;
    433 
    434 exit:
    435 	if( service )
    436 	{
    437 		CloseServiceHandle( service );
    438 	}
    439 	if( scm )
    440 	{
    441 		CloseServiceHandle( scm );
    442 	}
    443 	return( err );
    444 }
    445 
    446 //===========================================================================================================================
    447 //	RemoveService
    448 //===========================================================================================================================
    449 
    450 static OSStatus	RemoveService( LPCTSTR inName )
    451 {
    452 	OSStatus			err;
    453 	SC_HANDLE			scm;
    454 	SC_HANDLE			service;
    455 	BOOL				ok;
    456 	SERVICE_STATUS		status;
    457 
    458 	scm		= NULL;
    459 	service = NULL;
    460 
    461 	// Open a connection to the service.
    462 
    463 	scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
    464 	err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
    465 	require_noerr( err, exit );
    466 
    467 	service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
    468 	err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
    469 	require_noerr( err, exit );
    470 
    471 	// Stop the service, if it is not already stopped, then delete it.
    472 
    473 	ok = QueryServiceStatus( service, &status );
    474 	err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
    475 	require_noerr( err, exit );
    476 
    477 	if( status.dwCurrentState != SERVICE_STOPPED )
    478 	{
    479 		ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
    480 		check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
    481 	}
    482 
    483 	ok = DeleteService( service );
    484 	err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
    485 	require_noerr( err, exit );
    486 
    487 	ReportStatus( EVENTLOG_SUCCESS, "Removed service\n" );
    488 	err = ERROR_SUCCESS;
    489 
    490 exit:
    491 	if( service )
    492 	{
    493 		CloseServiceHandle( service );
    494 	}
    495 	if( scm )
    496 	{
    497 		CloseServiceHandle( scm );
    498 	}
    499 	return( err );
    500 }
    501 
    502 
    503 
    504 //===========================================================================================================================
    505 //	SetServiceParameters
    506 //===========================================================================================================================
    507 
    508 static OSStatus SetServiceParameters()
    509 {
    510 	DWORD 			value;
    511 	DWORD			valueLen = sizeof(DWORD);
    512 	DWORD			type;
    513 	OSStatus		err;
    514 	HKEY			key;
    515 
    516 	key = NULL;
    517 
    518 	//
    519 	// Add/Open Parameters section under service entry in registry
    520 	//
    521 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
    522 	require_noerr( err, exit );
    523 
    524 	//
    525 	// If the value isn't already there, then we create it
    526 	//
    527 	err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
    528 
    529 	if (err != ERROR_SUCCESS)
    530 	{
    531 		value = 1;
    532 
    533 		err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
    534 		require_noerr( err, exit );
    535 	}
    536 
    537 exit:
    538 
    539 	if ( key )
    540 	{
    541 		RegCloseKey( key );
    542 	}
    543 
    544 	return( err );
    545 }
    546 
    547 
    548 
    549 //===========================================================================================================================
    550 //	GetServiceParameters
    551 //===========================================================================================================================
    552 
    553 static OSStatus GetServiceParameters()
    554 {
    555 	DWORD 			value;
    556 	DWORD			valueLen;
    557 	DWORD			type;
    558 	OSStatus		err;
    559 	HKEY			key;
    560 
    561 	key = NULL;
    562 
    563 	//
    564 	// Add/Open Parameters section under service entry in registry
    565 	//
    566 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
    567 	require_noerr( err, exit );
    568 
    569 	valueLen = sizeof(DWORD);
    570 	err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
    571 	if (err == ERROR_SUCCESS)
    572 	{
    573 		gServiceManageLLRouting = (value) ? true : false;
    574 	}
    575 
    576 	valueLen = sizeof(DWORD);
    577 	err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
    578 	if (err == ERROR_SUCCESS)
    579 	{
    580 		gServiceCacheEntryCount = value;
    581 	}
    582 
    583 exit:
    584 
    585 	if ( key )
    586 	{
    587 		RegCloseKey( key );
    588 	}
    589 
    590 	return( err );
    591 }
    592 
    593 
    594 //===========================================================================================================================
    595 //	CheckFirewall
    596 //===========================================================================================================================
    597 
    598 static OSStatus CheckFirewall()
    599 {
    600 	DWORD 					value;
    601 	DWORD					valueLen;
    602 	DWORD					type;
    603 	ENUM_SERVICE_STATUS	*	lpService = NULL;
    604 	SC_HANDLE				sc = NULL;
    605 	HKEY					key = NULL;
    606 	BOOL					ok;
    607 	DWORD					bytesNeeded = 0;
    608 	DWORD					srvCount;
    609 	DWORD					resumeHandle = 0;
    610 	DWORD					srvType;
    611 	DWORD					srvState;
    612 	DWORD					dwBytes = 0;
    613 	DWORD					i;
    614 	BOOL					isRunning = FALSE;
    615 	OSStatus				err = kUnknownErr;
    616 
    617 	// Check to see if the firewall service is running.  If it isn't, then
    618 	// we want to return immediately
    619 
    620 	sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
    621 	err = translate_errno( sc, GetLastError(), kUnknownErr );
    622 	require_noerr( err, exit );
    623 
    624 	srvType		=	SERVICE_WIN32;
    625 	srvState	=	SERVICE_STATE_ALL;
    626 
    627 	for ( ;; )
    628 	{
    629 		// Call EnumServicesStatus using the handle returned by OpenSCManager
    630 
    631 		ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
    632 
    633 		if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
    634 		{
    635 			break;
    636 		}
    637 
    638 		if ( lpService )
    639 		{
    640 			free( lpService );
    641 		}
    642 
    643 		dwBytes = bytesNeeded;
    644 
    645 		lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
    646 		require_action( lpService, exit, err = mStatus_NoMemoryErr );
    647 	}
    648 
    649 	err = translate_errno( ok, GetLastError(), kUnknownErr );
    650 	require_noerr( err, exit );
    651 
    652 	for ( i = 0; i < srvCount; i++ )
    653 	{
    654 		if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
    655 		{
    656 			if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
    657 			{
    658 				isRunning = TRUE;
    659 			}
    660 
    661 			break;
    662 		}
    663 	}
    664 
    665 	require_action( isRunning, exit, err = kUnknownErr );
    666 
    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.
    672 
    673 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
    674 	require_noerr( err, exit );
    675 
    676 	valueLen = sizeof(DWORD);
    677 	err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
    678 
    679 	if ((err != ERROR_SUCCESS) || (value == 0))
    680 	{
    681 		wchar_t	fullPath[ MAX_PATH ];
    682 		DWORD	size;
    683 
    684 		// Get a full path to the executable
    685 
    686 		size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
    687 		err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
    688 		require_noerr( err, exit );
    689 
    690 		err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
    691 		require_noerr( err, exit );
    692 
    693 		value = 1;
    694 		err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
    695 		require_noerr( err, exit );
    696 	}
    697 
    698 exit:
    699 
    700 	if ( key )
    701 	{
    702 		RegCloseKey( key );
    703 	}
    704 
    705 	if ( lpService )
    706 	{
    707 		free( lpService );
    708 	}
    709 
    710 	if ( sc )
    711 	{
    712 		CloseServiceHandle ( sc );
    713 	}
    714 
    715 	return( err );
    716 }
    717 
    718 
    719 
    720 //===========================================================================================================================
    721 //	SetServiceInfo
    722 //===========================================================================================================================
    723 
    724 static OSStatus	SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
    725 {
    726 	OSStatus				err;
    727 	SC_LOCK					lock;
    728 	SC_HANDLE				service;
    729 	SERVICE_DESCRIPTION		description;
    730 	SERVICE_FAILURE_ACTIONS	actions;
    731 	SC_ACTION				action;
    732 	BOOL					ok;
    733 
    734 	check( inServiceName );
    735 	check( inDescription );
    736 
    737 	lock 	= NULL;
    738 	service	= NULL;
    739 
    740 	// Open the database (if not provided) and lock it to prevent other access while re-configuring.
    741 
    742 	if( !inSCM )
    743 	{
    744 		inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
    745 		err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
    746 		require_noerr( err, exit );
    747 	}
    748 
    749 	lock = LockServiceDatabase( inSCM );
    750 	err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
    751 	require_noerr( err, exit );
    752 
    753 	// Open a handle to the service.
    754 
    755 	service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
    756 	err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
    757 	require_noerr( err, exit );
    758 
    759 	// Change the description.
    760 
    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 );
    765 
    766 	actions.dwResetPeriod	=	INFINITE;
    767 	actions.lpRebootMsg		=	NULL;
    768 	actions.lpCommand		=	NULL;
    769 	actions.cActions		=	1;
    770 	actions.lpsaActions		=	&action;
    771 	action.Delay			=	500;
    772 	action.Type				=	SC_ACTION_RESTART;
    773 
    774 	ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
    775 	err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
    776 	require_noerr( err, exit );
    777 
    778 	err = ERROR_SUCCESS;
    779 
    780 exit:
    781 	// Close the service and release the lock.
    782 
    783 	if( service )
    784 	{
    785 		CloseServiceHandle( service );
    786 	}
    787 	if( lock )
    788 	{
    789 		UnlockServiceDatabase( lock );
    790 	}
    791 	return( err );
    792 }
    793 
    794 //===========================================================================================================================
    795 //	ReportStatus
    796 //===========================================================================================================================
    797 
    798 static void	ReportStatus( int inType, const char *inFormat, ... )
    799 {
    800 	if( !gServiceQuietMode )
    801 	{
    802 		va_list		args;
    803 
    804 		va_start( args, inFormat );
    805 		if( gServiceEventSource )
    806 		{
    807 			char				s[ 1024 ];
    808 			BOOL				ok;
    809 			const char *		array[ 1 ];
    810 
    811 			vsprintf( s, inFormat, args );
    812 			array[ 0 ] = s;
    813 			ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL );
    814 			check_translated_errno( ok, GetLastError(), kUnknownErr );
    815 		}
    816 		else
    817 		{
    818 			int		n;
    819 
    820 			n = vfprintf( stderr, inFormat, args );
    821 			check( n >= 0 );
    822 		}
    823 		va_end( args );
    824 	}
    825 }
    826 
    827 //===========================================================================================================================
    828 //	RunDirect
    829 //===========================================================================================================================
    830 
    831 int	RunDirect( int argc, LPTSTR argv[] )
    832 {
    833 	OSStatus		err;
    834 	BOOL			initialized;
    835    BOOL        ok;
    836 
    837 	initialized = FALSE;
    838 
    839 	// Install a Console Control Handler to handle things like control-c signals.
    840 
    841 	ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
    842 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
    843 	require_noerr( err, exit );
    844 
    845 	err = ServiceSpecificInitialize( argc, argv );
    846 	require_noerr( err, exit );
    847 	initialized = TRUE;
    848 
    849 	// Run the service. This does not return until the service quits or is stopped.
    850 
    851 	ReportStatus( EVENTLOG_INFORMATION_TYPE, "Running service directly\n" );
    852 
    853 	err = ServiceSpecificRun( argc, argv );
    854 	require_noerr( err, exit );
    855 
    856 	// Clean up.
    857 
    858 exit:
    859 	if( initialized )
    860 	{
    861 		ServiceSpecificFinalize( argc, argv );
    862 	}
    863 	return( err );
    864 }
    865 
    866 #if 0
    867 #pragma mark -
    868 #endif
    869 
    870 //===========================================================================================================================
    871 //	ServiceMain
    872 //===========================================================================================================================
    873 
    874 static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
    875 {
    876 	OSStatus		err;
    877 	BOOL			ok;
    878 
    879 	err = ServiceSetupEventLogging();
    880 	check_noerr( err );
    881 
    882 	err = GetServiceParameters();
    883 	check_noerr( err );
    884 
    885 	// Initialize the service status and register the service control handler with the name of the service.
    886 
    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;
    894 
    895 	gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
    896 	err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
    897 	require_noerr( err, exit );
    898 
    899 	// Mark the service as starting.
    900 
    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 );
    906 
    907 	// Run the service. This does not return until the service quits or is stopped.
    908 
    909 	err = ServiceRun( (int) argc, argv );
    910 	if( err != kNoErr )
    911 	{
    912 		gServiceStatus.dwWin32ExitCode				= ERROR_SERVICE_SPECIFIC_ERROR;
    913 		gServiceStatus.dwServiceSpecificExitCode 	= (DWORD) err;
    914 	}
    915 
    916 	// Service-specific work is done so mark the service as stopped.
    917 
    918 	gServiceStatus.dwCurrentState = SERVICE_STOPPED;
    919 	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
    920 	check_translated_errno( ok, GetLastError(), kParamErr );
    921 
    922 	// Note: The service status handle should not be closed according to Microsoft documentation.
    923 
    924 exit:
    925 	if( gServiceEventSource )
    926 	{
    927 		ok = DeregisterEventSource( gServiceEventSource );
    928 		check_translated_errno( ok, GetLastError(), kUnknownErr );
    929 		gServiceEventSource = NULL;
    930 	}
    931 }
    932 
    933 //===========================================================================================================================
    934 //	ServiceSetupEventLogging
    935 //===========================================================================================================================
    936 
    937 static OSStatus	ServiceSetupEventLogging( void )
    938 {
    939 	OSStatus			err;
    940 	HKEY				key;
    941 	LPCTSTR				s;
    942 	DWORD				typesSupported;
    943 	TCHAR				path[ MAX_PATH ];
    944 	DWORD 				n;
    945 
    946 	key = NULL;
    947 
    948 	// Add/Open source name as a sub-key under the Application key in the EventLog registry key.
    949 
    950 	s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
    951 	err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
    952 	require_noerr( err, exit );
    953 
    954 	// Add the name to the EventMessageFile subkey.
    955 
    956 	path[ 0 ] = '\0';
    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 );
    961 
    962 	// Set the supported event types in the TypesSupported subkey.
    963 
    964 	typesSupported = 0
    965 					 | EVENTLOG_SUCCESS
    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 );
    973 
    974 	// Set up the event source.
    975 
    976 	gServiceEventSource = RegisterEventSource( NULL, kServiceName );
    977 	err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
    978 	require_noerr( err, exit );
    979 
    980 exit:
    981 	if( key )
    982 	{
    983 		RegCloseKey( key );
    984 	}
    985 	return( err );
    986 }
    987 
    988 //===========================================================================================================================
    989 //	HandlePowerSuspend
    990 //===========================================================================================================================
    991 
    992 static void HandlePowerSuspend( void * v )
    993 {
    994 	LARGE_INTEGER	timeout;
    995 	BOOL			ok;
    996 
    997 	( void ) v;
    998 
    999 	dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerSuspend\n" );
   1000 
   1001 	gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
   1002 
   1003 	if ( gMDNSRecord.SystemWakeOnLANEnabled )
   1004 	{
   1005 		ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
   1006 		check( ok );
   1007 	}
   1008 
   1009 	mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
   1010 }
   1011 
   1012 
   1013 //===========================================================================================================================
   1014 //	HandlePowerResumeSuspend
   1015 //===========================================================================================================================
   1016 
   1017 static void HandlePowerResumeSuspend( void * v )
   1018 {
   1019 	( void ) v;
   1020 
   1021 	dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerResumeSuspend\n" );
   1022 
   1023 	if ( gSPSWakeupEvent )
   1024 	{
   1025 		CancelWaitableTimer( gSPSWakeupEvent );
   1026 	}
   1027 
   1028 	if ( gSPSSleepEvent )
   1029 	{
   1030 		CancelWaitableTimer( gSPSSleepEvent );
   1031 	}
   1032 
   1033 	mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
   1034 }
   1035 
   1036 
   1037 //===========================================================================================================================
   1038 //	ServiceControlHandler
   1039 //===========================================================================================================================
   1040 
   1041 static DWORD WINAPI	ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
   1042 {
   1043 	BOOL		setStatus;
   1044 	BOOL		ok;
   1045 
   1046 	DEBUG_UNUSED( inEventData );
   1047 	DEBUG_UNUSED( inContext );
   1048 
   1049 	setStatus = TRUE;
   1050 	switch( inControl )
   1051 	{
   1052 		case SERVICE_CONTROL_STOP:
   1053 		case SERVICE_CONTROL_SHUTDOWN:
   1054 			dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
   1055 
   1056 			ServiceStop();
   1057 			setStatus = FALSE;
   1058 			break;
   1059 
   1060 		case SERVICE_CONTROL_POWEREVENT:
   1061 
   1062 			if (inEventType == PBT_APMSUSPEND)
   1063 			{
   1064 				dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
   1065 
   1066 				QueueUserAPC( ( PAPCFUNC ) HandlePowerSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
   1067 			}
   1068 			else if (inEventType == PBT_APMRESUMESUSPEND)
   1069 			{
   1070 				dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
   1071 
   1072 				QueueUserAPC( ( PAPCFUNC ) HandlePowerResumeSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
   1073 			}
   1074 
   1075 			break;
   1076 
   1077 		default:
   1078 			dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
   1079 			break;
   1080 	}
   1081 
   1082 	if( setStatus && gServiceStatusHandle )
   1083 	{
   1084 		ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
   1085 		check_translated_errno( ok, GetLastError(), kUnknownErr );
   1086 	}
   1087 
   1088 	return NO_ERROR;
   1089 }
   1090 
   1091 //===========================================================================================================================
   1092 //	ServiceRun
   1093 //===========================================================================================================================
   1094 
   1095 static OSStatus	ServiceRun( int argc, LPTSTR argv[] )
   1096 {
   1097 	OSStatus		err;
   1098 	BOOL			initialized;
   1099 	BOOL			ok;
   1100 
   1101 	DEBUG_UNUSED( argc );
   1102 	DEBUG_UNUSED( argv );
   1103 
   1104 	initialized = FALSE;
   1105 
   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.
   1111 
   1112 	gServiceStatus.dwCurrentState = SERVICE_RUNNING;
   1113 	ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
   1114 	check_translated_errno( ok, GetLastError(), kParamErr );
   1115 
   1116 	// Initialize the service-specific stuff
   1117 
   1118 	err = ServiceSpecificInitialize( argc, argv );
   1119 	require_noerr( err, exit );
   1120 	initialized = TRUE;
   1121 
   1122 	err = CheckFirewall();
   1123 	check_noerr( err );
   1124 
   1125 	if ( err )
   1126 	{
   1127 		gRetryFirewall = TRUE;
   1128 	}
   1129 
   1130 	// Run the service-specific stuff. This does not return until the service quits or is stopped.
   1131 
   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 );
   1136 
   1137 	// Service stopped. Clean up and we're done.
   1138 
   1139 exit:
   1140 	if( initialized )
   1141 	{
   1142 		ServiceSpecificFinalize( argc, argv );
   1143 	}
   1144 	return( err );
   1145 }
   1146 
   1147 //===========================================================================================================================
   1148 //	ServiceStop
   1149 //===========================================================================================================================
   1150 
   1151 static void	ServiceStop( void )
   1152 {
   1153 	BOOL			ok;
   1154 	OSStatus		err;
   1155 
   1156 	// Signal the event to cause the service to exit.
   1157 
   1158 	if( gServiceStatusHandle )
   1159 	{
   1160 		gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
   1161 		ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
   1162 		check_translated_errno( ok, GetLastError(), kParamErr );
   1163 	}
   1164 
   1165 	err = ServiceSpecificStop();
   1166 	check_noerr( err );
   1167 }
   1168 
   1169 #if 0
   1170 #pragma mark -
   1171 #pragma mark == Service Specific ==
   1172 #endif
   1173 
   1174 //===========================================================================================================================
   1175 //	ServiceSpecificInitialize
   1176 //===========================================================================================================================
   1177 
   1178 static OSStatus	ServiceSpecificInitialize( int argc, LPTSTR argv[] )
   1179 {
   1180 	OSVERSIONINFO osInfo;
   1181 	OSStatus err;
   1182 	BOOL ok;
   1183 
   1184 	DEBUG_UNUSED( argc );
   1185 	DEBUG_UNUSED( argv );
   1186 
   1187 	mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
   1188 	mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
   1189 
   1190 	gPlatformStorage.registerWaitableEventFunc = RegisterWaitableEvent;
   1191 	gPlatformStorage.unregisterWaitableEventFunc = UnregisterWaitableEvent;
   1192 	gPlatformStorage.reportStatusFunc = ReportStatus;
   1193 
   1194 	err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
   1195 	require_noerr( err, exit);
   1196 
   1197 	err = SetupNotifications();
   1198 	check_noerr( err );
   1199 
   1200 	err = udsserver_init(mDNSNULL, 0);
   1201 	require_noerr( err, exit);
   1202 
   1203 	//
   1204 	// Get the version of Windows that we're running on
   1205 	//
   1206 	osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
   1207 	ok = GetVersionEx( &osInfo );
   1208 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
   1209 	require_noerr( err, exit );
   1210 	gOSMajorVersion = osInfo.dwMajorVersion;
   1211 	gOSMinorVersion = osInfo.dwMinorVersion;
   1212 
   1213 	SetLLRoute( &gMDNSRecord );
   1214 
   1215 exit:
   1216 	if( err != kNoErr )
   1217 	{
   1218 		ServiceSpecificFinalize( argc, argv );
   1219 	}
   1220 	return( err );
   1221 }
   1222 
   1223 //===========================================================================================================================
   1224 //	ServiceSpecificRun
   1225 //===========================================================================================================================
   1226 
   1227 static OSStatus	ServiceSpecificRun( int argc, LPTSTR argv[] )
   1228 {
   1229 	HANDLE	*	waitList;
   1230 	int			waitListCount;
   1231 	DWORD		timeout;
   1232 	DWORD		result;
   1233 	BOOL		done;
   1234 	mStatus		err;
   1235 
   1236 	DEBUG_UNUSED( argc );
   1237 	DEBUG_UNUSED( argv );
   1238 
   1239 	timeout = ( gRetryFirewall ) ? kRetryFirewallPeriod : INFINITE;
   1240 
   1241 	err = SetupInterfaceList( &gMDNSRecord );
   1242 	check( !err );
   1243 
   1244 	err = uDNS_SetupDNSConfig( &gMDNSRecord );
   1245 	check( !err );
   1246 
   1247 	done = FALSE;
   1248 
   1249 	// Main event loop.
   1250 
   1251 	while( !done )
   1252 	{
   1253 		waitList		= NULL;
   1254 		waitListCount	= 0;
   1255 
   1256 		err = SetupWaitList( &gMDNSRecord, &waitList, &waitListCount );
   1257 		require_noerr( err, exit );
   1258 
   1259 		gEventSourceListChanged = FALSE;
   1260 
   1261 		while ( !gEventSourceListChanged )
   1262 		{
   1263 			static mDNSs32 RepeatedBusy = 0;
   1264 			mDNSs32 nextTimerEvent;
   1265 
   1266 			// Give the mDNS core a chance to do its work and determine next event time.
   1267 
   1268 			nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
   1269 
   1270 			if      ( nextTimerEvent < 0)					nextTimerEvent = 0;
   1271 			else if ( nextTimerEvent > (0x7FFFFFFF / 1000))	nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
   1272 			else											nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
   1273 
   1274 			// Debugging sanity check, to guard against CPU spins
   1275 
   1276 			if ( nextTimerEvent > 0 )
   1277 			{
   1278 				RepeatedBusy = 0;
   1279 			}
   1280 			else
   1281 			{
   1282 				nextTimerEvent = 1;
   1283 
   1284 				if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
   1285 				{
   1286 					ShowTaskSchedulingError( &gMDNSRecord );
   1287 					RepeatedBusy = 0;
   1288 				}
   1289 			}
   1290 
   1291 			if ( gMDNSRecord.ShutdownTime )
   1292 			{
   1293 				mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
   1294 
   1295 				if ( mDNS_ExitNow( &gMDNSRecord, now ) )
   1296 				{
   1297 					mDNS_FinalExit( &gMDNSRecord );
   1298 					done = TRUE;
   1299 					break;
   1300 				}
   1301 
   1302 				if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
   1303 				{
   1304 					nextTimerEvent = gMDNSRecord.ShutdownTime;
   1305 				}
   1306 			}
   1307 
   1308 			// Wait until something occurs (e.g. cancel, incoming packet, or timeout).
   1309 			//
   1310 			// Note: There seems to be a bug in WinSock with respect to Alertable I/O. According
   1311 			// to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
   1312 			// callbacks will only be invoked during the following calls (when the caller sets
   1313 			// the appropriate flag):
   1314 			//
   1315 			// - SleepEx
   1316 			// - WaitForSingleObjectEx
   1317 			// - WaitForMultipleObjectsEx
   1318 			// - SignalObjectAndWait
   1319 			// - MsgWaitForMultipleObjectsEx
   1320 			//
   1321 			// However, we have seen callbacks be invoked during calls to bind() (and maybe others). If there
   1322 			// weren't a bug, then socket events would only be queued during the call to WaitForMultipleObjects() and
   1323 			// we'd only have to check them once afterwards. However since that doesn't seem to be the case, we'll
   1324 			// check the queue both before we call WaitForMultipleObjects() and after.
   1325 
   1326 			DispatchSocketEvents( &gMDNSRecord );
   1327 			result = WaitForMultipleObjectsEx( ( DWORD ) waitListCount, waitList, FALSE, (DWORD) nextTimerEvent, TRUE );
   1328 			check( result != WAIT_FAILED );
   1329 			DispatchSocketEvents( &gMDNSRecord );
   1330 
   1331 			if ( result != WAIT_FAILED )
   1332 			{
   1333 				if ( result == WAIT_TIMEOUT )
   1334 				{
   1335 					// Next task timeout occurred. Loop back up to give mDNS core a chance to work.
   1336 
   1337 					dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
   1338 					continue;
   1339 				}
   1340 				else if ( result == WAIT_IO_COMPLETION )
   1341 				{
   1342 					dlog( kDebugLevelChatty - 1, DEBUG_NAME "i/o completion\n" );
   1343 					continue;
   1344 				}
   1345 				else if ( result == kWaitListStopEvent )
   1346 				{
   1347 					// Stop event. Set the done flag and break to exit.
   1348 
   1349 					dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
   1350 					udsserver_exit();
   1351 					mDNS_StartExit( &gMDNSRecord );
   1352 					break;
   1353 				}
   1354 				else if( result == kWaitListInterfaceListChangedEvent )
   1355 				{
   1356 					int		inBuffer;
   1357 					int		outBuffer;
   1358 					DWORD	outSize;
   1359 
   1360 					// It would be nice to come up with a more elegant solution to this, but it seems that
   1361 					// GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
   1362 					// as a simple workaround, we'll pause for a couple of seconds before processing the change.
   1363 
   1364 					// We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
   1365 					// for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
   1366 					// second on top of that to account for machine load or some other exigency.
   1367 
   1368 					Sleep( 2000 );
   1369 
   1370 					// Interface list changed event. Break out of the inner loop to re-setup the wait list.
   1371 
   1372 					InterfaceListDidChange( &gMDNSRecord );
   1373 
   1374 					// reset the event handler
   1375 					inBuffer	= 0;
   1376 					outBuffer	= 0;
   1377 					err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
   1378 					if( err < 0 )
   1379 					{
   1380 						check( errno_compat() == WSAEWOULDBLOCK );
   1381 					}
   1382 				}
   1383 				else if ( result == kWaitListComputerDescriptionEvent )
   1384 				{
   1385 					// The computer description might have changed
   1386 
   1387 					ComputerDescriptionDidChange( &gMDNSRecord );
   1388 					udsserver_handle_configchange( &gMDNSRecord );
   1389 
   1390 					// and reset the event handler
   1391 					if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
   1392 					{
   1393 						err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
   1394 						check_noerr( err );
   1395 					}
   1396 				}
   1397 				else if ( result == kWaitListTCPIPEvent )
   1398 				{
   1399 					// The TCP/IP might have changed
   1400 
   1401 					TCPIPConfigDidChange( &gMDNSRecord );
   1402 					udsserver_handle_configchange( &gMDNSRecord );
   1403 
   1404 					// and reset the event handler
   1405 
   1406 					if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
   1407 					{
   1408 						err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
   1409 						check_noerr( err );
   1410 					}
   1411 				}
   1412 				else if ( result == kWaitListDynDNSEvent )
   1413 				{
   1414 					// The DynDNS config might have changed
   1415 
   1416 					DynDNSConfigDidChange( &gMDNSRecord );
   1417 					udsserver_handle_configchange( &gMDNSRecord );
   1418 
   1419 					// and reset the event handler
   1420 
   1421 					if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
   1422 					{
   1423 						err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
   1424 						check_noerr( err );
   1425 					}
   1426 				}
   1427 				else if ( result == kWaitListFileShareEvent )
   1428 				{
   1429 					// File sharing changed
   1430 
   1431 					FileSharingDidChange( &gMDNSRecord );
   1432 
   1433 					// and reset the event handler
   1434 
   1435 					if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
   1436 					{
   1437 						err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
   1438 						check_noerr( err );
   1439 					}
   1440 				}
   1441 				else if ( result == kWaitListFirewallEvent )
   1442 				{
   1443 					// Firewall configuration changed
   1444 
   1445 					FirewallDidChange( &gMDNSRecord );
   1446 
   1447 					// and reset the event handler
   1448 
   1449 					if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
   1450 					{
   1451 						err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
   1452 						check_noerr( err );
   1453 					}
   1454 				}
   1455 				else if ( result == kWaitListAdvertisedServicesEvent )
   1456 				{
   1457 					// Ultimately we'll want to manage multiple services, but right now the only service
   1458 					// we'll be managing is SMB.
   1459 
   1460 					FileSharingDidChange( &gMDNSRecord );
   1461 
   1462 					// and reset the event handler
   1463 
   1464 					if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
   1465 					{
   1466 						err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
   1467 						check_noerr( err );
   1468 					}
   1469 				}
   1470 				else if ( result == kWaitListSPSWakeupEvent )
   1471 				{
   1472 					LARGE_INTEGER timeout;
   1473 
   1474 					ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
   1475 
   1476 					timeout.QuadPart  = kSPSMaintenanceWakePeriod;
   1477 					timeout.QuadPart *= kSecondsTo100NSUnits;
   1478 
   1479 					SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
   1480 				}
   1481 				else if ( result == kWaitListSPSSleepEvent )
   1482 				{
   1483 					ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
   1484 
   1485 					// Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
   1486 					// call HandlePowerSuspend() explicity.  This will reset the
   1487 					// maintenance wake timers.
   1488 
   1489 					HandlePowerSuspend( NULL );
   1490 					SetSuspendState( FALSE, FALSE, FALSE );
   1491 				}
   1492 				else
   1493 				{
   1494 					int waitItemIndex;
   1495 
   1496 					waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
   1497 					dlog( kDebugLevelChatty, DEBUG_NAME "waitable event on %d\n", waitItemIndex );
   1498 					check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
   1499 
   1500 					if ( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
   1501 					{
   1502 						HANDLE	signaledEvent;
   1503 						int		n = 0;
   1504 
   1505 						signaledEvent = waitList[ waitItemIndex ];
   1506 
   1507 						// If gCurrentSource is not NULL, then this routine has been called
   1508 						// re-entrantly which should never happen.
   1509 
   1510 						check( !gCurrentSource );
   1511 
   1512 						for ( gCurrentSource = gEventSourceList; gCurrentSource; )
   1513 						{
   1514 							EventSource * current = gCurrentSource;
   1515 
   1516 							if ( gCurrentSource->event == signaledEvent )
   1517 							{
   1518 								gCurrentSource->handler( &gMDNSRecord, gCurrentSource->event, gCurrentSource->context );
   1519 								++n;
   1520 								break;
   1521 							}
   1522 
   1523 							// If the current node was removed as a result of calling
   1524 							// the handler, then gCurrentSource was already incremented to
   1525 							// the next node.  If it wasn't removed, then increment it
   1526 							// ourselves
   1527 
   1528 							if ( gCurrentSource == current )
   1529 							{
   1530 								gCurrentSource = gCurrentSource->next;
   1531 							}
   1532 						}
   1533 
   1534 						gCurrentSource = NULL;
   1535 
   1536 						check( n > 0 );
   1537 					}
   1538 					else
   1539 					{
   1540 						dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
   1541 					}
   1542 				}
   1543 			}
   1544 			else
   1545 			{
   1546 				Sleep( 3 * 1000 );
   1547 
   1548 				err = SetupInterfaceList( &gMDNSRecord );
   1549 				check( !err );
   1550 
   1551 				err = uDNS_SetupDNSConfig( &gMDNSRecord );
   1552 				check( !err );
   1553 
   1554 				break;
   1555 			}
   1556 		}
   1557 
   1558 		if ( waitList )
   1559 		{
   1560 			free( waitList );
   1561 			waitList = NULL;
   1562 			waitListCount = 0;
   1563 		}
   1564 	}
   1565 
   1566 exit:
   1567 
   1568 	return( 0 );
   1569 }
   1570 
   1571 //===========================================================================================================================
   1572 //	ServiceSpecificStop
   1573 //===========================================================================================================================
   1574 
   1575 static OSStatus	ServiceSpecificStop( void )
   1576 {
   1577 	OSStatus	err;
   1578 	BOOL	 	ok;
   1579 
   1580 	ok = SetEvent(gStopEvent);
   1581 	err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
   1582 	require_noerr( err, exit );
   1583 exit:
   1584 	return( err );
   1585 }
   1586 
   1587 //===========================================================================================================================
   1588 //	ServiceSpecificFinalize
   1589 //===========================================================================================================================
   1590 
   1591 static void	ServiceSpecificFinalize( int argc, LPTSTR argv[] )
   1592 {
   1593 	DEBUG_UNUSED( argc );
   1594 	DEBUG_UNUSED( argv );
   1595 
   1596 	//
   1597 	// clean up any open sessions
   1598 	//
   1599 	while ( gEventSourceList )
   1600 	{
   1601 		UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
   1602 	}
   1603 
   1604 	//
   1605 	// clean up the notifications
   1606 	//
   1607 	TearDownNotifications();
   1608 
   1609 	//
   1610 	// clean up loaded library
   1611 	//
   1612 
   1613 	if( gIPHelperLibraryInstance )
   1614 	{
   1615 		gGetIpInterfaceEntryFunctionPtr = NULL;
   1616 
   1617 		FreeLibrary( gIPHelperLibraryInstance );
   1618 		gIPHelperLibraryInstance = NULL;
   1619 	}
   1620 }
   1621 
   1622 
   1623 //===========================================================================================================================
   1624 //	SetupNotifications
   1625 //===========================================================================================================================
   1626 
   1627 mDNSlocal mStatus	SetupNotifications()
   1628 {
   1629 	mStatus				err;
   1630 	SocketRef			sock;
   1631 	unsigned long		param;
   1632 	int					inBuffer;
   1633 	int					outBuffer;
   1634 	DWORD				outSize;
   1635 
   1636 	gStopEvent	=	CreateEvent(NULL, FALSE, FALSE, NULL);
   1637 	err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
   1638 	require_noerr( err, exit );
   1639 
   1640 	// Register to listen for address list changes.
   1641 
   1642 	gInterfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   1643 	err = translate_errno( gInterfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1644 	require_noerr( err, exit );
   1645 
   1646 	sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
   1647 	err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
   1648 	require_noerr( err, exit );
   1649 	gInterfaceListChangedSocket = sock;
   1650 
   1651 	// Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
   1652 	// when a change to the interface list is detected.
   1653 
   1654 	param = 1;
   1655 	err = ioctlsocket( sock, FIONBIO, &param );
   1656 	err = translate_errno( err == 0, errno_compat(), kUnknownErr );
   1657 	require_noerr( err, exit );
   1658 
   1659 	inBuffer	= 0;
   1660 	outBuffer	= 0;
   1661 	err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
   1662 	if( err < 0 )
   1663 	{
   1664 		check( errno_compat() == WSAEWOULDBLOCK );
   1665 	}
   1666 
   1667 	err = WSAEventSelect( sock, gInterfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
   1668 	err = translate_errno( err == 0, errno_compat(), kUnknownErr );
   1669 	require_noerr( err, exit );
   1670 
   1671 	gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
   1672 	err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1673 	require_noerr( err, exit );
   1674 
   1675 	err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
   1676 	check_translated_errno( err == 0, errno_compat(), kNameErr );
   1677 
   1678 	if ( gDescKey != NULL )
   1679 	{
   1680 		err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
   1681 		require_noerr( err, exit );
   1682 	}
   1683 
   1684 	// This will catch all changes to tcp/ip networking, including changes to the domain search list
   1685 
   1686 	gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   1687 	err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1688 	require_noerr( err, exit );
   1689 
   1690 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
   1691 	require_noerr( err, exit );
   1692 
   1693 	err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
   1694 	require_noerr( err, exit );
   1695 
   1696 	// This will catch all changes to ddns configuration
   1697 
   1698 	gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   1699 	err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1700 	require_noerr( err, exit );
   1701 
   1702 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
   1703 	require_noerr( err, exit );
   1704 
   1705 	err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
   1706 	require_noerr( err, exit );
   1707 
   1708 	// This will catch all changes to file sharing
   1709 
   1710 	gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   1711 	err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1712 	require_noerr( err, exit );
   1713 
   1714 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
   1715 
   1716 	// Just to make sure that initialization doesn't fail on some old OS
   1717 	// that doesn't have this key, we'll only add the notification if
   1718 	// the key exists.
   1719 
   1720 	if ( !err )
   1721 	{
   1722 		err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
   1723 		require_noerr( err, exit );
   1724 	}
   1725 	else
   1726 	{
   1727 		err = mStatus_NoError;
   1728 	}
   1729 
   1730 	// This will catch changes to the Windows firewall
   1731 
   1732 	gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   1733 	err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1734 	require_noerr( err, exit );
   1735 
   1736 	// Just to make sure that initialization doesn't fail on some old OS
   1737 	// that doesn't have this key, we'll only add the notification if
   1738 	// the key exists.
   1739 
   1740 	err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
   1741 
   1742 	if ( !err )
   1743 	{
   1744 		err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
   1745 		require_noerr( err, exit );
   1746 	}
   1747 	else
   1748 	{
   1749 		err = mStatus_NoError;
   1750 	}
   1751 
   1752 	// This will catch all changes to advertised services configuration
   1753 
   1754 	gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   1755 	err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
   1756 	require_noerr( err, exit );
   1757 
   1758 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
   1759 	require_noerr( err, exit );
   1760 
   1761 	err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
   1762 	require_noerr( err, exit );
   1763 
   1764 	gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
   1765 	err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
   1766 	require_noerr( err, exit );
   1767 
   1768 	gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
   1769 	err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
   1770 	require_noerr( err, exit );
   1771 
   1772 	gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   1773 	err = translate_errno( gUDSEvent, ( mStatus ) GetLastError(), kUnknownErr );
   1774 	require_noerr( err, exit );
   1775 
   1776 exit:
   1777 	if( err )
   1778 	{
   1779 		TearDownNotifications();
   1780 	}
   1781 	return( err );
   1782 }
   1783 
   1784 //===========================================================================================================================
   1785 //	TearDownNotifications
   1786 //===========================================================================================================================
   1787 
   1788 mDNSlocal mStatus	TearDownNotifications()
   1789 {
   1790 	if ( gStopEvent )
   1791 	{
   1792 		CloseHandle( gStopEvent );
   1793 		gStopEvent = NULL;
   1794 	}
   1795 
   1796 	if( IsValidSocket( gInterfaceListChangedSocket ) )
   1797 	{
   1798 		close_compat( gInterfaceListChangedSocket );
   1799 		gInterfaceListChangedSocket = kInvalidSocketRef;
   1800 	}
   1801 
   1802 	if( gInterfaceListChangedEvent )
   1803 	{
   1804 		CloseHandle( gInterfaceListChangedEvent );
   1805 		gInterfaceListChangedEvent = 0;
   1806 	}
   1807 
   1808 	if ( gDescChangedEvent != NULL )
   1809 	{
   1810 		CloseHandle( gDescChangedEvent );
   1811 		gDescChangedEvent = NULL;
   1812 	}
   1813 
   1814 	if ( gDescKey != NULL )
   1815 	{
   1816 		RegCloseKey( gDescKey );
   1817 		gDescKey = NULL;
   1818 	}
   1819 
   1820 	if ( gTcpipChangedEvent != NULL )
   1821 	{
   1822 		CloseHandle( gTcpipChangedEvent );
   1823 		gTcpipChangedEvent = NULL;
   1824 	}
   1825 
   1826 	if ( gDdnsChangedEvent != NULL )
   1827 	{
   1828 		CloseHandle( gDdnsChangedEvent );
   1829 		gDdnsChangedEvent = NULL;
   1830 	}
   1831 
   1832 	if ( gDdnsKey != NULL )
   1833 	{
   1834 		RegCloseKey( gDdnsKey );
   1835 		gDdnsKey = NULL;
   1836 	}
   1837 
   1838 	if ( gFileSharingChangedEvent != NULL )
   1839 	{
   1840 		CloseHandle( gFileSharingChangedEvent );
   1841 		gFileSharingChangedEvent = NULL;
   1842 	}
   1843 
   1844 	if ( gFileSharingKey != NULL )
   1845 	{
   1846 		RegCloseKey( gFileSharingKey );
   1847 		gFileSharingKey = NULL;
   1848 	}
   1849 
   1850 	if ( gFirewallChangedEvent != NULL )
   1851 	{
   1852 		CloseHandle( gFirewallChangedEvent );
   1853 		gFirewallChangedEvent = NULL;
   1854 	}
   1855 
   1856 	if ( gFirewallKey != NULL )
   1857 	{
   1858 		RegCloseKey( gFirewallKey );
   1859 		gFirewallKey = NULL;
   1860 	}
   1861 
   1862 	if ( gAdvertisedServicesChangedEvent != NULL )
   1863 	{
   1864 		CloseHandle( gAdvertisedServicesChangedEvent );
   1865 		gAdvertisedServicesChangedEvent = NULL;
   1866 	}
   1867 
   1868 	if ( gAdvertisedServicesKey != NULL )
   1869 	{
   1870 		RegCloseKey( gAdvertisedServicesKey );
   1871 		gAdvertisedServicesKey = NULL;
   1872 	}
   1873 
   1874 	if ( gSPSWakeupEvent )
   1875 	{
   1876 		CloseHandle( gSPSWakeupEvent );
   1877 		gSPSWakeupEvent = NULL;
   1878 	}
   1879 
   1880 	if ( gSPSSleepEvent )
   1881 	{
   1882 		CloseHandle( gSPSSleepEvent );
   1883 		gSPSSleepEvent = NULL;
   1884 	}
   1885 
   1886 	return( mStatus_NoError );
   1887 }
   1888 
   1889 
   1890 //===========================================================================================================================
   1891 //	RegisterWaitableEvent
   1892 //===========================================================================================================================
   1893 
   1894 static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
   1895 {
   1896 	EventSource * source;
   1897 	mStatus err = mStatus_NoError;
   1898 
   1899 	( void ) inMDNS;
   1900 	check( event );
   1901 	check( handler );
   1902 
   1903 	source = ( EventSource* ) malloc( sizeof( EventSource ) );
   1904 	require_action( source, exit, err = mStatus_NoMemoryErr );
   1905 	mDNSPlatformMemZero( source, sizeof( EventSource ) );
   1906 	source->event = event;
   1907 	source->context = context;
   1908 	source->handler = handler;
   1909 
   1910 	source->next			= gEventSourceList;
   1911 	gEventSourceList		= source;
   1912 	gEventSourceListChanged	= TRUE;
   1913 	gEventSources++;
   1914 
   1915 exit:
   1916 
   1917 	return err;
   1918 }
   1919 
   1920 
   1921 //===========================================================================================================================
   1922 //	UnregisterWaitableEvent
   1923 //===========================================================================================================================
   1924 
   1925 static void UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event )
   1926 {
   1927 	EventSource	*	current	= gEventSourceList;
   1928 	EventSource	*	last	= NULL;
   1929 
   1930 	( void ) inMDNS;
   1931 	check( event );
   1932 
   1933 	while ( current )
   1934 	{
   1935 		if ( current->event == event )
   1936 		{
   1937 			if ( last == NULL )
   1938 			{
   1939 				gEventSourceList = current->next;
   1940 			}
   1941 			else
   1942 			{
   1943 				last->next = current->next;
   1944 			}
   1945 
   1946 			gEventSourceListChanged = TRUE;
   1947 
   1948 			// Protect against removing the node that we happen
   1949 			// to be looking at as we iterate through the event
   1950 			// source list in ServiceSpecificRun()
   1951 
   1952 			if ( current == gCurrentSource )
   1953 			{
   1954 				gCurrentSource = current->next;
   1955 			}
   1956 
   1957 			gEventSources--;
   1958 			free( current );
   1959 
   1960 			break;
   1961 		}
   1962 
   1963 		last	= current;
   1964 		current	= current->next;
   1965 	}
   1966 }
   1967 
   1968 
   1969 //===========================================================================================================================
   1970 //	SetupWaitList
   1971 //===========================================================================================================================
   1972 
   1973 mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
   1974 {
   1975 	int				waitListCount;
   1976 	HANDLE		*	waitList;
   1977 	HANDLE		*	waitItemPtr;
   1978 	EventSource	*	source;
   1979 	mStatus			err;
   1980 
   1981 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
   1982 
   1983 	( void ) inMDNS;
   1984 	check( inMDNS->p );
   1985 	check( outWaitList );
   1986 	check( outWaitListCount );
   1987 
   1988 	// Allocate an array to hold all the objects to wait on.
   1989 
   1990 	waitListCount = kWaitListFixedItemCount + gEventSources;
   1991 	waitList = ( HANDLE* ) malloc( waitListCount * sizeof( *waitList ) );
   1992 	require_action( waitList, exit, err = mStatus_NoMemoryErr );
   1993 	waitItemPtr = waitList;
   1994 
   1995 	// Add the fixed wait items to the beginning of the list.
   1996 
   1997 	*waitItemPtr++	=	gStopEvent;
   1998 	*waitItemPtr++	=	gInterfaceListChangedEvent;
   1999 	*waitItemPtr++	=	gDescChangedEvent;
   2000 	*waitItemPtr++	=	gTcpipChangedEvent;
   2001 	*waitItemPtr++	=	gDdnsChangedEvent;
   2002 	*waitItemPtr++	=	gFileSharingChangedEvent;
   2003 	*waitItemPtr++	=	gFirewallChangedEvent;
   2004 	*waitItemPtr++	=	gAdvertisedServicesChangedEvent;
   2005 	*waitItemPtr++	=	gSPSWakeupEvent;
   2006 	*waitItemPtr++	=	gSPSSleepEvent;
   2007 
   2008 	for ( source = gEventSourceList; source; source = source->next )
   2009 	{
   2010 		*waitItemPtr++ = source->event;
   2011 	}
   2012 
   2013 	check( ( int )( waitItemPtr - waitList ) == waitListCount );
   2014 
   2015 	*outWaitList 		= waitList;
   2016 	*outWaitListCount	= waitListCount;
   2017 	waitList			= NULL;
   2018 	err					= mStatus_NoError;
   2019 
   2020 exit:
   2021 
   2022 	if( waitList )
   2023 	{
   2024 		free( waitList );
   2025 	}
   2026 
   2027 	dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list done (err=%d %m)\n", err, err );
   2028 	return( err );
   2029 }
   2030 
   2031 
   2032 //===========================================================================================================================
   2033 //	CoreCallback
   2034 //===========================================================================================================================
   2035 
   2036 static void
   2037 CoreCallback(mDNS * const inMDNS, mStatus status)
   2038 {
   2039 	if (status == mStatus_ConfigChanged)
   2040 	{
   2041 		SetLLRoute( inMDNS );
   2042 	}
   2043 }
   2044 
   2045 
   2046 //===========================================================================================================================
   2047 //	UDSCanAccept
   2048 //===========================================================================================================================
   2049 
   2050 mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
   2051 {
   2052 	( void ) inMDNS;
   2053 	( void ) event;
   2054 
   2055 	if ( gUDSCallback )
   2056 	{
   2057 		gUDSCallback( ( int ) gUDSSocket, 0, context );
   2058 	}
   2059 }
   2060 
   2061 
   2062 //===========================================================================================================================
   2063 //	UDSCanRead
   2064 //===========================================================================================================================
   2065 
   2066 mDNSlocal void UDSCanRead( TCPSocket * sock )
   2067 {
   2068 	udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
   2069 
   2070 	if ( callback )
   2071 	{
   2072 		callback( (int) sock->fd, 0, sock->userContext );
   2073 	}
   2074 }
   2075 
   2076 
   2077 //===========================================================================================================================
   2078 //	udsSupportAddFDToEventLoop
   2079 //===========================================================================================================================
   2080 
   2081 
   2082 mStatus
   2083 udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
   2084 {
   2085 	mStatus err = mStatus_NoError;
   2086 
   2087 	// We are using some knowledge of what is being passed to us here.  If the fd is a listen socket,
   2088 	// then the "callback" parameter is NULL.  If it is an actual read/write socket, then the "callback"
   2089 	// parameter is not null. This is important because we use waitable events for the listen socket
   2090 	// and alertable I/O for the read/write sockets.
   2091 
   2092 	if ( context )
   2093 	{
   2094 		TCPSocket * sock;
   2095 
   2096 		sock = malloc( sizeof( TCPSocket ) );
   2097 		require_action( sock, exit, err = mStatus_NoMemoryErr );
   2098 		mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
   2099 
   2100 		sock->fd				= (SOCKET) fd;
   2101 		sock->readEventHandler	= UDSCanRead;
   2102 		sock->userCallback		= callback;
   2103 		sock->userContext		= context;
   2104 		sock->m					= &gMDNSRecord;
   2105 
   2106 		err = TCPAddSocket( sock->m, sock );
   2107 		require_noerr( err, exit );
   2108 
   2109 		*platform_data = sock;
   2110 	}
   2111 	else
   2112 	{
   2113 		gUDSSocket		= fd;
   2114 		gUDSCallback	= callback;
   2115 		gUDSEvent		= CreateEvent( NULL, FALSE, FALSE, NULL );
   2116 		err = translate_errno( gUDSEvent, (mStatus) GetLastError(), kUnknownErr );
   2117 		require_noerr( err, exit );
   2118 		err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE );
   2119 		err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );
   2120 		require_noerr( err, exit );
   2121 		err = RegisterWaitableEvent( &gMDNSRecord, gUDSEvent, context, UDSCanAccept );
   2122 		require_noerr( err, exit );
   2123 	}
   2124 
   2125 exit:
   2126 
   2127 	return err;
   2128 }
   2129 
   2130 
   2131 int
   2132 udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
   2133 {
   2134 	TCPSocket	*	sock;
   2135 	mDNSBool		closed;
   2136 	int				ret;
   2137 
   2138 	( void ) flags;
   2139 
   2140 	sock = ( TCPSocket* ) platform_data;
   2141 	require_action( sock, exit, ret = -1 );
   2142 	require_action( sock->fd == fd, exit, ret = -1 );
   2143 
   2144 	ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
   2145 
   2146 	if ( closed )
   2147 	{
   2148 		ret = 0;
   2149 	}
   2150 
   2151 exit:
   2152 
   2153 	return ret;
   2154 }
   2155 
   2156 
   2157 mStatus
   2158 udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)		// Note: This also CLOSES the socket
   2159 {
   2160 	mStatus err = kNoErr;
   2161 
   2162 	if ( platform_data != NULL )
   2163 	{
   2164 		TCPSocket * sock;
   2165 
   2166 		dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
   2167 		sock = ( TCPSocket* ) platform_data;
   2168 		check( sock->fd == fd );
   2169 		mDNSPlatformTCPCloseConnection( sock );
   2170 	}
   2171 	else if ( gUDSEvent != NULL )
   2172 	{
   2173 		UnregisterWaitableEvent( &gMDNSRecord, gUDSEvent );
   2174 		WSAEventSelect( fd, gUDSEvent, 0 );
   2175 		CloseHandle( gUDSEvent );
   2176 		gUDSEvent = NULL;
   2177 	}
   2178 
   2179 	return err;
   2180 }
   2181 
   2182 
   2183 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
   2184 	{
   2185 	(void)m;
   2186 	(void)delay;
   2187 	// No-op, for now
   2188 	}
   2189 
   2190 
   2191 //===========================================================================================================================
   2192 //	SystemWakeForNetworkAccess
   2193 //===========================================================================================================================
   2194 
   2195 mDNSu8
   2196 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
   2197 {
   2198 	HKEY					key = NULL;
   2199 	DWORD					dwSize;
   2200 	DWORD					enabled;
   2201 	mDNSu8					ok;
   2202 	SYSTEM_POWER_STATUS		powerStatus;
   2203 	time_t					startTime;
   2204 	time_t					nextWakeupTime;
   2205 	int						delta;
   2206 	DWORD					err;
   2207 
   2208 	dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
   2209 
   2210 	// Make sure we have a timer
   2211 
   2212 	require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
   2213 	require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
   2214 
   2215 	// Make sure the user enabled bonjour sleep proxy client
   2216 
   2217 	err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
   2218 	require_action( !err, exit, ok = FALSE );
   2219 	dwSize = sizeof( DWORD );
   2220 	err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
   2221 	require_action( !err, exit, ok = FALSE );
   2222 	require_action( enabled, exit, ok = FALSE );
   2223 
   2224 	// Make sure machine is on AC power
   2225 
   2226 	ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
   2227 	require_action( ok, exit, ok = FALSE );
   2228 	require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
   2229 
   2230 	// Now make sure we have a network interface that does wake-on-lan
   2231 
   2232 	ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
   2233 	require_action( ok, exit, ok = FALSE );
   2234 
   2235 	// Now make sure we have advertised services. Doesn't make sense to
   2236 	// enable sleep proxy if we have no multicast services that could
   2237 	// potentially wake us up.
   2238 
   2239 	ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
   2240 	require_action( ok, exit, ok = FALSE );
   2241 
   2242 	// Calculate next wake up time
   2243 
   2244 	startTime		= time( NULL );					// Seconds since midnight January 1, 1970
   2245 	nextWakeupTime	= startTime + ( 120 * 60 );		// 2 hours later
   2246 
   2247 	if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
   2248 	{
   2249 		nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
   2250 	}
   2251 
   2252 	// Finally calculate the next relative wakeup time
   2253 
   2254 	delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
   2255 	ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
   2256 
   2257 	// Convert seconds to 100 nanosecond units expected by SetWaitableTimer
   2258 
   2259 	timeout->QuadPart  = -delta;
   2260 	timeout->QuadPart *= kSecondsTo100NSUnits;
   2261 
   2262 	ok = TRUE;
   2263 
   2264 exit:
   2265 
   2266 	if ( key )
   2267 	{
   2268 		RegCloseKey( key );
   2269 	}
   2270 
   2271 	return ok;
   2272 }
   2273 
   2274 
   2275 //===========================================================================================================================
   2276 //	HaveRoute
   2277 //===========================================================================================================================
   2278 
   2279 static bool
   2280 HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
   2281 {
   2282 	PMIB_IPFORWARDTABLE	pIpForwardTable	= NULL;
   2283 	DWORD				dwSize			= 0;
   2284 	BOOL				bOrder			= FALSE;
   2285 	OSStatus			err;
   2286 	bool				found			= false;
   2287 	unsigned long int	i;
   2288 
   2289 	//
   2290 	// Find out how big our buffer needs to be.
   2291 	//
   2292 	err = GetIpForwardTable(NULL, &dwSize, bOrder);
   2293 	require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
   2294 
   2295 	//
   2296 	// Allocate the memory for the table
   2297 	//
   2298 	pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
   2299 	require_action( pIpForwardTable, exit, err = kNoMemoryErr );
   2300 
   2301 	//
   2302 	// Now get the table.
   2303 	//
   2304 	err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
   2305 	require_noerr( err, exit );
   2306 
   2307 	//
   2308 	// Search for the row in the table we want.
   2309 	//
   2310 	for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
   2311 	{
   2312 		if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
   2313 		{
   2314 			memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
   2315 			found = true;
   2316 			break;
   2317 		}
   2318 	}
   2319 
   2320 exit:
   2321 
   2322 	if ( pIpForwardTable != NULL )
   2323 	{
   2324 		free(pIpForwardTable);
   2325 	}
   2326 
   2327 	return found;
   2328 }
   2329 
   2330 
   2331 //===========================================================================================================================
   2332 //	IsValidAddress
   2333 //===========================================================================================================================
   2334 
   2335 static bool
   2336 IsValidAddress( const char * addr )
   2337 {
   2338 	return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
   2339 }
   2340 
   2341 
   2342 //===========================================================================================================================
   2343 //	GetAdditionalMetric
   2344 //===========================================================================================================================
   2345 
   2346 static ULONG
   2347 GetAdditionalMetric( DWORD ifIndex )
   2348 {
   2349 	ULONG metric = 0;
   2350 
   2351 	if( !gIPHelperLibraryInstance )
   2352 	{
   2353 		gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
   2354 
   2355 		gGetIpInterfaceEntryFunctionPtr =
   2356 				(GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
   2357 
   2358 		if( !gGetIpInterfaceEntryFunctionPtr )
   2359 		{
   2360 			BOOL ok;
   2361 
   2362 			ok = FreeLibrary( gIPHelperLibraryInstance );
   2363 			check_translated_errno( ok, GetLastError(), kUnknownErr );
   2364 			gIPHelperLibraryInstance = NULL;
   2365 		}
   2366 	}
   2367 
   2368 	if ( gGetIpInterfaceEntryFunctionPtr )
   2369 	{
   2370 		MIB_IPINTERFACE_ROW row;
   2371 		DWORD err;
   2372 
   2373 		ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
   2374 		row.Family = AF_INET;
   2375 		row.InterfaceIndex = ifIndex;
   2376 		err = gGetIpInterfaceEntryFunctionPtr( &row );
   2377 		require_noerr( err, exit );
   2378 		metric = row.Metric + 256;
   2379 	}
   2380 
   2381 exit:
   2382 
   2383 	return metric;
   2384 }
   2385 
   2386 
   2387 //===========================================================================================================================
   2388 //	SetLLRoute
   2389 //===========================================================================================================================
   2390 
   2391 static OSStatus
   2392 SetLLRoute( mDNS * const inMDNS )
   2393 {
   2394 	OSStatus err = kNoErr;
   2395 
   2396 	DEBUG_UNUSED( inMDNS );
   2397 
   2398 	//
   2399 	// <rdar://problem/4096464> Don't call SetLLRoute on loopback
   2400 	// <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
   2401 	//
   2402 	// Don't mess w/ the routing table on Vista and later OSes, as
   2403 	// they have a permanent route to link-local addresses. Otherwise,
   2404 	// set a route to link local addresses (169.254.0.0)
   2405 	//
   2406 	if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
   2407 	{
   2408 		DWORD				ifIndex;
   2409 		MIB_IPFORWARDROW	rowExtant;
   2410 		bool				addRoute;
   2411 		MIB_IPFORWARDROW	row;
   2412 
   2413 		ZeroMemory(&row, sizeof(row));
   2414 
   2415 		err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
   2416 		require_noerr( err, exit );
   2417 		row.dwForwardDest		= inet_addr(kLLNetworkAddr);
   2418 		row.dwForwardIfIndex	= ifIndex;
   2419 		row.dwForwardMask		= inet_addr(kLLNetworkAddrMask);
   2420 		row.dwForwardType		= 3;
   2421 		row.dwForwardProto		= MIB_IPPROTO_NETMGMT;
   2422 		row.dwForwardAge		= 0;
   2423 		row.dwForwardPolicy		= 0;
   2424 		row.dwForwardMetric1	= 20 + GetAdditionalMetric( ifIndex );
   2425 		row.dwForwardMetric2	= (DWORD) - 1;
   2426 		row.dwForwardMetric3	= (DWORD) - 1;
   2427 		row.dwForwardMetric4	= (DWORD) - 1;
   2428 		row.dwForwardMetric5	= (DWORD) - 1;
   2429 
   2430 		addRoute = true;
   2431 
   2432 		//
   2433 		// check to make sure we don't already have a route
   2434 		//
   2435 		if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
   2436 		{
   2437 			//
   2438 			// set the age to 0 so that we can do a memcmp.
   2439 			//
   2440 			rowExtant.dwForwardAge = 0;
   2441 
   2442 			//
   2443 			// check to see if this route is the same as our route
   2444 			//
   2445 			if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
   2446 			{
   2447 				//
   2448 				// if it isn't then delete this entry
   2449 				//
   2450 				DeleteIpForwardEntry(&rowExtant);
   2451 			}
   2452 			else
   2453 			{
   2454 				//
   2455 				// else it is, so we don't want to create another route
   2456 				//
   2457 				addRoute = false;
   2458 			}
   2459 		}
   2460 
   2461 		if (addRoute && row.dwForwardNextHop)
   2462 		{
   2463 			err = CreateIpForwardEntry(&row);
   2464 			check_noerr( err );
   2465 		}
   2466 	}
   2467 
   2468 exit:
   2469 
   2470 	return ( err );
   2471 }
   2472 
   2473 
   2474 //===========================================================================================================================
   2475 //	GetRouteDestination
   2476 //===========================================================================================================================
   2477 
   2478 static OSStatus
   2479 GetRouteDestination(DWORD * ifIndex, DWORD * address)
   2480 {
   2481 	struct in_addr		ia;
   2482 	IP_ADAPTER_INFO	*	pAdapterInfo	=	NULL;
   2483 	IP_ADAPTER_INFO	*	pAdapter		=	NULL;
   2484 	ULONG				bufLen;
   2485 	mDNSBool			done			=	mDNSfalse;
   2486 	OSStatus			err;
   2487 
   2488 	//
   2489 	// GetBestInterface will fail if there is no default gateway
   2490 	// configured.  If that happens, we will just take the first
   2491 	// interface in the list. MSDN support says there is no surefire
   2492 	// way to manually determine what the best interface might
   2493 	// be for a particular network address.
   2494 	//
   2495 	ia.s_addr	=	inet_addr(kLLNetworkAddr);
   2496 	err			=	GetBestInterface(*(IPAddr*) &ia, ifIndex);
   2497 
   2498 	if (err)
   2499 	{
   2500 		*ifIndex = 0;
   2501 	}
   2502 
   2503 	//
   2504 	// Make an initial call to GetAdaptersInfo to get
   2505 	// the necessary size into the bufLen variable
   2506 	//
   2507 	err = GetAdaptersInfo( NULL, &bufLen);
   2508 	require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
   2509 
   2510 	pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
   2511 	require_action( pAdapterInfo, exit, err = kNoMemoryErr );
   2512 
   2513 	err = GetAdaptersInfo( pAdapterInfo, &bufLen);
   2514 	require_noerr( err, exit );
   2515 
   2516 	pAdapter	=	pAdapterInfo;
   2517 	err			=	kUnknownErr;
   2518 
   2519 	// <rdar://problem/3718122>
   2520 	// <rdar://problem/5652098>
   2521 	//
   2522 	// Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
   2523 	//
   2524 	// If these interfaces are active (i.e., has a non-zero IP Address),
   2525 	// then we want to disable routing table modifications.
   2526 
   2527 	while (pAdapter)
   2528 	{
   2529 		if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
   2530 			 ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
   2531 		{
   2532 			dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
   2533 			goto exit;
   2534 		}
   2535 
   2536 		pAdapter = pAdapter->Next;
   2537 	}
   2538 
   2539 	while ( !done )
   2540 	{
   2541 		pAdapter	=	pAdapterInfo;
   2542 		err			=	kUnknownErr;
   2543 
   2544 		while (pAdapter)
   2545 		{
   2546 			// If we don't have an interface selected, choose the first one that is of type ethernet and
   2547 			// has a valid IP Address
   2548 
   2549 			if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
   2550 			{
   2551 				*address =	inet_addr( pAdapter->IpAddressList.IpAddress.String );
   2552 				*ifIndex =  pAdapter->Index;
   2553 				err		 =	kNoErr;
   2554 				break;
   2555 			}
   2556 
   2557 			pAdapter = pAdapter->Next;
   2558 		}
   2559 
   2560 		// If we found the right interface, or we weren't trying to find a specific interface then we're done
   2561 
   2562 		if ( !err || !( *ifIndex) )
   2563 		{
   2564 			done = mDNStrue;
   2565 		}
   2566 
   2567 		// Otherwise, try again by wildcarding the interface
   2568 
   2569 		else
   2570 		{
   2571 			*ifIndex = 0;
   2572 		}
   2573 	}
   2574 
   2575 exit:
   2576 
   2577 	if ( pAdapterInfo != NULL )
   2578 	{
   2579 		free( pAdapterInfo );
   2580 	}
   2581 
   2582 	return( err );
   2583 }
   2584 
   2585 
   2586 static bool
   2587 IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
   2588 {
   2589 	return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
   2590 		    (pAdapter->AddressLength == 6) &&
   2591 		    (pAdapter->Address[0] == 0x44) &&
   2592 		    (pAdapter->Address[1] == 0x45) &&
   2593 		    (pAdapter->Address[2] == 0x53) &&
   2594 		    (pAdapter->Address[3] == 0x54) &&
   2595 		    (pAdapter->Address[4] == 0x42) &&
   2596 			(pAdapter->Address[5] == 0x00)) ? true : false;
   2597 }
   2598 
   2599 
   2600 static bool
   2601 IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
   2602 {
   2603 	return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description  ) ) != NULL ) ? true : false;
   2604 }
   2605 
   2606 
   2607 static bool
   2608 IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
   2609 {
   2610 	return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
   2611 		    (pAdapter->AddressLength == 6) &&
   2612 		    (pAdapter->Address[0] == 0x00) &&
   2613 		    (pAdapter->Address[1] == 0x05) &&
   2614 		    (pAdapter->Address[2] == 0x9a) &&
   2615 		    (pAdapter->Address[3] == 0x3c) &&
   2616 		    (pAdapter->Address[4] == 0x7a) &&
   2617 			(pAdapter->Address[5] == 0x00)) ? true : false;
   2618 }
   2619 
   2620 
   2621 static const char *
   2622 strnistr( const char * string, const char * subString, size_t max )
   2623 {
   2624 	size_t       subStringLen;
   2625 	size_t       offset;
   2626 	size_t       maxOffset;
   2627 	size_t       stringLen;
   2628 	const char * pPos;
   2629 
   2630 	if ( ( string == NULL ) || ( subString == NULL ) )
   2631 	{
   2632 		return string;
   2633 	}
   2634 
   2635 	stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
   2636 
   2637 	if ( stringLen == 0 )
   2638 	{
   2639 		return NULL;
   2640 	}
   2641 
   2642 	subStringLen = strlen( subString );
   2643 
   2644 	if ( subStringLen == 0 )
   2645 	{
   2646 		return string;
   2647 	}
   2648 
   2649 	if ( subStringLen > stringLen )
   2650 	{
   2651 		return NULL;
   2652 	}
   2653 
   2654 	maxOffset = stringLen - subStringLen;
   2655 	pPos      = string;
   2656 
   2657 	for ( offset = 0; offset <= maxOffset; offset++ )
   2658 	{
   2659 		if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
   2660 		{
   2661 			return pPos;
   2662 		}
   2663 
   2664 		pPos++;
   2665 	}
   2666 
   2667 	return NULL;
   2668 }
   2669 
   2670