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
78static CacheEntity gRRCache[RR_CACHE_SIZE];
79#if 0
80#pragma mark == Structures ==
81#endif
82
83//===========================================================================================================================
84//	Structures
85//===========================================================================================================================
86
87typedef struct EventSource
88{
89	HANDLE							event;
90	void						*	context;
91	RegisterWaitableEventHandler	handler;
92	struct EventSource			*	next;
93} EventSource;
94
95static BOOL											gEventSourceListChanged = FALSE;
96static EventSource								*	gEventSourceList = NULL;
97static EventSource								*	gCurrentSource = NULL;
98static 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//===========================================================================================================================
120static void			Usage( void );
121static BOOL WINAPI	ConsoleControlHandler( DWORD inControlEvent );
122static OSStatus		InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
123static OSStatus		RemoveService( LPCTSTR inName );
124static OSStatus		SetServiceParameters();
125static OSStatus		GetServiceParameters();
126static OSStatus		CheckFirewall();
127static OSStatus		SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
128static void			ReportStatus( int inType, const char *inFormat, ... );
129
130static void WINAPI	ServiceMain( DWORD argc, LPTSTR argv[] );
131static OSStatus		ServiceSetupEventLogging( void );
132static DWORD WINAPI	ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
133
134static OSStatus		ServiceRun( int argc, LPTSTR argv[] );
135static void			ServiceStop( void );
136
137static OSStatus		ServiceSpecificInitialize( int argc, LPTSTR  argv[] );
138static OSStatus		ServiceSpecificRun( int argc, LPTSTR argv[] );
139static OSStatus		ServiceSpecificStop( void );
140static void			ServiceSpecificFinalize( int argc, LPTSTR argv[] );
141static mStatus		SetupNotifications();
142static mStatus		TearDownNotifications();
143static mStatus		RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
144static void			UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event );
145static mStatus		SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
146static void			UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context );
147static void			UDSCanRead( TCPSocket * sock );
148static void			HandlePowerSuspend( void * v );
149static void			HandlePowerResumeSuspend( void * v );
150static void			CoreCallback(mDNS * const inMDNS, mStatus result);
151static mDNSu8		SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
152static OSStatus		GetRouteDestination(DWORD * ifIndex, DWORD * address);
153static OSStatus		SetLLRoute( mDNS * const inMDNS );
154static bool			HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
155static bool			IsValidAddress( const char * addr );
156static bool			IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
157static bool			IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
158static bool			IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
159static 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
184DEBUG_LOCAL	mDNS_PlatformSupport		gPlatformStorage;
185DEBUG_LOCAL BOOL						gServiceQuietMode		= FALSE;
186DEBUG_LOCAL SERVICE_TABLE_ENTRY			gServiceDispatchTable[] =
187{
188	{ kServiceName,	ServiceMain },
189	{ NULL, 		NULL }
190};
191DEBUG_LOCAL SOCKET						gInterfaceListChangedSocket	= INVALID_SOCKET;
192DEBUG_LOCAL HANDLE						gInterfaceListChangedEvent	= NULL;
193DEBUG_LOCAL HKEY						gDescKey					= NULL;
194DEBUG_LOCAL HANDLE						gDescChangedEvent			= NULL;	// Computer description changed event
195DEBUG_LOCAL HKEY						gTcpipKey					= NULL;
196DEBUG_LOCAL HANDLE						gTcpipChangedEvent			= NULL;	// TCP/IP config changed
197DEBUG_LOCAL HKEY						gDdnsKey					= NULL;
198DEBUG_LOCAL HANDLE						gDdnsChangedEvent			= NULL;	// DynDNS config changed
199DEBUG_LOCAL HKEY						gFileSharingKey				= NULL;
200DEBUG_LOCAL HANDLE						gFileSharingChangedEvent	= NULL;	// File Sharing changed
201DEBUG_LOCAL HKEY						gFirewallKey				= NULL;
202DEBUG_LOCAL HANDLE						gFirewallChangedEvent		= NULL;	// Firewall changed
203DEBUG_LOCAL HKEY						gAdvertisedServicesKey		= NULL;
204DEBUG_LOCAL HANDLE						gAdvertisedServicesChangedEvent	= NULL; // Advertised services changed
205DEBUG_LOCAL SERVICE_STATUS				gServiceStatus;
206DEBUG_LOCAL SERVICE_STATUS_HANDLE		gServiceStatusHandle 	= NULL;
207DEBUG_LOCAL HANDLE						gServiceEventSource		= NULL;
208DEBUG_LOCAL bool						gServiceAllowRemote		= false;
209DEBUG_LOCAL int							gServiceCacheEntryCount	= 0;	// 0 means to use the DNS-SD default.
210DEBUG_LOCAL bool						gServiceManageLLRouting = true;
211DEBUG_LOCAL int							gWaitCount				= 0;
212DEBUG_LOCAL HANDLE					*	gWaitList				= NULL;
213DEBUG_LOCAL HANDLE						gStopEvent				= NULL;
214DEBUG_LOCAL HANDLE						gSPSWakeupEvent			= NULL;
215DEBUG_LOCAL HANDLE						gSPSSleepEvent			= NULL;
216DEBUG_LOCAL HANDLE						gUDSEvent				= NULL;
217DEBUG_LOCAL SocketRef					gUDSSocket				= 0;
218DEBUG_LOCAL udsEventCallback			gUDSCallback			= NULL;
219DEBUG_LOCAL BOOL						gRetryFirewall			= FALSE;
220DEBUG_LOCAL DWORD						gOSMajorVersion;
221DEBUG_LOCAL DWORD						gOSMinorVersion;
222
223typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
224mDNSlocal HMODULE								gIPHelperLibraryInstance		= NULL;
225mDNSlocal GetIpInterfaceEntryFunctionPtr		gGetIpInterfaceEntryFunctionPtr	= NULL;
226
227
228#if 0
229#pragma mark -
230#endif
231
232//===========================================================================================================================
233//	Main
234//===========================================================================================================================
235int	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
325exit:
326	dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
327	_CrtDumpMemoryLeaks();
328	return( (int) err );
329}
330
331//===========================================================================================================================
332//	Usage
333//===========================================================================================================================
334
335static 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
356static 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
379exit:
380	return( handled );
381}
382
383//===========================================================================================================================
384//	InstallService
385//===========================================================================================================================
386
387static 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
434exit:
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
450static 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
490exit:
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
508static 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
537exit:
538
539	if ( key )
540	{
541		RegCloseKey( key );
542	}
543
544	return( err );
545}
546
547
548
549//===========================================================================================================================
550//	GetServiceParameters
551//===========================================================================================================================
552
553static 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
583exit:
584
585	if ( key )
586	{
587		RegCloseKey( key );
588	}
589
590	return( err );
591}
592
593
594//===========================================================================================================================
595//	CheckFirewall
596//===========================================================================================================================
597
598static 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
698exit:
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
724static 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
780exit:
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
798static 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
831int	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
858exit:
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
874static 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
924exit:
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
937static 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
980exit:
981	if( key )
982	{
983		RegCloseKey( key );
984	}
985	return( err );
986}
987
988//===========================================================================================================================
989//	HandlePowerSuspend
990//===========================================================================================================================
991
992static 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
1017static 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
1041static 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
1095static 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
1139exit:
1140	if( initialized )
1141	{
1142		ServiceSpecificFinalize( argc, argv );
1143	}
1144	return( err );
1145}
1146
1147//===========================================================================================================================
1148//	ServiceStop
1149//===========================================================================================================================
1150
1151static 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
1178static 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
1215exit:
1216	if( err != kNoErr )
1217	{
1218		ServiceSpecificFinalize( argc, argv );
1219	}
1220	return( err );
1221}
1222
1223//===========================================================================================================================
1224//	ServiceSpecificRun
1225//===========================================================================================================================
1226
1227static 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
1566exit:
1567
1568	return( 0 );
1569}
1570
1571//===========================================================================================================================
1572//	ServiceSpecificStop
1573//===========================================================================================================================
1574
1575static 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 );
1583exit:
1584	return( err );
1585}
1586
1587//===========================================================================================================================
1588//	ServiceSpecificFinalize
1589//===========================================================================================================================
1590
1591static 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
1627mDNSlocal 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
1776exit:
1777	if( err )
1778	{
1779		TearDownNotifications();
1780	}
1781	return( err );
1782}
1783
1784//===========================================================================================================================
1785//	TearDownNotifications
1786//===========================================================================================================================
1787
1788mDNSlocal 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
1894static 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
1915exit:
1916
1917	return err;
1918}
1919
1920
1921//===========================================================================================================================
1922//	UnregisterWaitableEvent
1923//===========================================================================================================================
1924
1925static 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
1973mDNSlocal 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
2020exit:
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
2036static void
2037CoreCallback(mDNS * const inMDNS, mStatus status)
2038{
2039	if (status == mStatus_ConfigChanged)
2040	{
2041		SetLLRoute( inMDNS );
2042	}
2043}
2044
2045
2046//===========================================================================================================================
2047//	UDSCanAccept
2048//===========================================================================================================================
2049
2050mDNSlocal 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
2066mDNSlocal 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
2082mStatus
2083udsSupportAddFDToEventLoop( 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
2125exit:
2126
2127	return err;
2128}
2129
2130
2131int
2132udsSupportReadFD( 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
2151exit:
2152
2153	return ret;
2154}
2155
2156
2157mStatus
2158udsSupportRemoveFDFromEventLoop( 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
2183mDNSexport 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
2195mDNSu8
2196SystemWakeForNetworkAccess( 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
2264exit:
2265
2266	if ( key )
2267	{
2268		RegCloseKey( key );
2269	}
2270
2271	return ok;
2272}
2273
2274
2275//===========================================================================================================================
2276//	HaveRoute
2277//===========================================================================================================================
2278
2279static bool
2280HaveRoute( 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
2320exit:
2321
2322	if ( pIpForwardTable != NULL )
2323	{
2324		free(pIpForwardTable);
2325	}
2326
2327	return found;
2328}
2329
2330
2331//===========================================================================================================================
2332//	IsValidAddress
2333//===========================================================================================================================
2334
2335static bool
2336IsValidAddress( const char * addr )
2337{
2338	return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
2339}
2340
2341
2342//===========================================================================================================================
2343//	GetAdditionalMetric
2344//===========================================================================================================================
2345
2346static ULONG
2347GetAdditionalMetric( 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
2381exit:
2382
2383	return metric;
2384}
2385
2386
2387//===========================================================================================================================
2388//	SetLLRoute
2389//===========================================================================================================================
2390
2391static OSStatus
2392SetLLRoute( 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
2468exit:
2469
2470	return ( err );
2471}
2472
2473
2474//===========================================================================================================================
2475//	GetRouteDestination
2476//===========================================================================================================================
2477
2478static OSStatus
2479GetRouteDestination(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
2575exit:
2576
2577	if ( pAdapterInfo != NULL )
2578	{
2579		free( pAdapterInfo );
2580	}
2581
2582	return( err );
2583}
2584
2585
2586static bool
2587IsNortelVPN( 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
2600static bool
2601IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
2602{
2603	return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description  ) ) != NULL ) ? true : false;
2604}
2605
2606
2607static bool
2608IsCiscoVPN( 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
2621static const char *
2622strnistr( 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